void IClient::handleBinary(ByteArray &piece, string &str, shared_ptr<Invoke> &invoke, size_t size) { if (piece.getPosition() >= size) return; ByteArray *byteArray = nullptr; size_t position = piece.getPosition(); size_t param_index = 0; //FIND WHICH PARAMETER IS BINARY for (size_t i = 0; i < invoke->size(); i++) if (invoke->at(i)->getType() == "ByteArray") { const ByteArray &ba = invoke->at(i)->referValue<ByteArray>(); if (ba.size() < ba.capacity()) { param_index = i; byteArray = (ByteArray*)&ba; break; } } //IF THERE'S NOT BINARY TYPE if(byteArray == nullptr) return; //CALCULATE SIZE size_t totalSize = byteArray->capacity(); size_t leftSize = totalSize - byteArray->size(); size_t writeSize = std::min(size - position, leftSize); //AND WRITES byteArray->insert ( byteArray->end(), piece.begin() + position, piece.begin() + (position + writeSize) ); piece.setPosition( position + writeSize ); // IF NOT FULFILLED, RETURNS if (byteArray->size() < byteArray->capacity()) return; //IF LAST BINARY for(size_t i = param_index + 1; i < invoke->size(); i++) if(invoke->at(i)->getType() == "ByteArray") return; // SHIFTS _replyData(invoke); //IS LAST BINARY, THEN CLEAR invoke.reset(); //IF BYTES ARE LEFT, CALL HANDLE_STRING handleString(piece, str, invoke, size); }
int Work::handleMsg(unsigned short id, ByteArray &ba, int fd) { cout<< "Protocol id: "<< id << endl; switch(id) { case 100://--login struct LoginRecvMsg loginRecv; memset(&loginRecv, 0, sizeof(loginRecv)); memcpy(&loginRecv, &ba.buf[ba.getPosition()], sizeof(loginRecv)); cout<<"UserInfo: "<<loginRecv.userID<<" "<<loginRecv.password<<endl; ba.plusPosition(sizeof(loginRecv)); cout<<"position is: "<<ba.getPosition() << " available is: "<<ba.getBytesAvailable() << endl; verifyUserData(loginRecv, fd); // cout<< ba.readUTFBytes(100) << endl; // cout<< ba.readUTFBytes(100) << endl; break; case 200://--register struct RegRecvMsg RegRecv; memset(&RegRecv, 0, sizeof(RegRecv)); memcpy(&RegRecv, &ba.buf[ba.getPosition()], sizeof(RegRecv)); cout<<"UserInfo: "<<RegRecv.userID<<" "<<RegRecv.password<<endl; ba.plusPosition(sizeof(RegRecv)); cout<<"position is: "<<ba.getPosition() << " available is: "<<ba.getBytesAvailable() << endl; verifyRegEvent(RegRecv, fd); break; case 300://--friend list struct FriendListRecvMsg friendListRecv; memset(&friendListRecv, 0, sizeof(friendListRecv)); memcpy(&friendListRecv, &ba.buf[ba.getPosition()], sizeof(friendListRecv)); cout<<"UserID: "<<friendListRecv.userID<<endl; ba.plusPosition(sizeof(FriendListRecvMsg)); cout<<"position is: "<<ba.getPosition() << " available is: "<<ba.getBytesAvailable() << endl; sendFriendList(friendListRecv,fd); break; case 500://---message struct SendMessageRecvMsg recvMsg; memset(&recvMsg, 0, sizeof(recvMsg)); memcpy(&recvMsg, &ba.buf[ba.getPosition()], ba.getBytesAvailable()); cout<<"Send User ID: "<<recvMsg.senderUserID << " Recive User ID: "<<recvMsg.receiverUserID << " Message Info: "<<recvMsg.messageInfo<<endl; ba.plusPosition(ba.getBytesAvailable()); cout<<"position is: "<<ba.getPosition() << " available is: "<<ba.getBytesAvailable() << endl; handleRecvMsgInfo(recvMsg, fd); break; default: cout<<"Unkonwn Protocol " << id << endl; break; } return 0; }
void IClient::handleString(ByteArray &piece, string &str, shared_ptr<Invoke> &baInvoke, size_t size) { static size_t CLOSED_PARENTHESIS = string("</invoke>").size(); if (piece.getPosition() >= size) return; // LIST OF INVOKE MESSAGES list<shared_ptr<Invoke>> invokeList; // READ STRING string &pieceString = piece.read<string>(); str.append(pieceString); WeakString wstr = str; vector<WeakString> &wstrArray = wstr.betweens("<invoke ", "</invoke>"); for (size_t i = 0; i < wstrArray.size(); i++) { string &message = "<invoke " + wstrArray[i].str() + "</invoke>"; shared_ptr<Invoke> invoke( new Invoke() ); invoke->construct(make_shared<XML>(message)); invokeList.push_back(invoke); } /*list<shared_ptr<Invoke>> invokeList; pair<size_t, size_t> posPair = {-1, -1}; pair<size_t, size_t> sizePair = {0, 0}; pair<size_t, size_t> indexPair = {0, 0}; size_t endIndex = -1; while (true) { // FIND WORDS pair<size_t, size_t> myPair = { str.find("<invoke ", indexPair.first), str.find("</invoke>", indexPair.second) }; // COUNTS if (myPair.first != -1) { sizePair.first++; indexPair.first = myPair.first + string("<invoke ").size(); } if (myPair.second != -1) { sizePair.second++; indexPair.second = myPair.second + string("</invoke>").size(); } // IF AN INVOKE MESSAGE HAS FOUND if (sizePair.first == sizePair.second && sizePair.first != 0) { if (posPair.first == -1 && posPair.second == -1) posPair = myPair; else posPair.second = myPair.second; endIndex = posPair.second + string("</invoke>").size(); WeakString wstr(str.data() + posPair.first, str.data() + endIndex); shared_ptr<XML> xml(new XML(wstr)); shared_ptr<Invoke> invoke(new Invoke()); invoke->construct(xml); cout << invoke->toXML()->toString() << endl; invokeList.push_back(invoke); posPair = { -1, -1 }; } else if (myPair.first != -1 && posPair.first == -1) posPair.first = myPair.first; }*/ //BASIC DATA /*list<shared_ptr<Invoke>> invokeList; unique_ptr<pair<size_t, size_t>> indexPair(nullptr); pair<size_t, size_t> sizePair = {0, 0}; size_t startIndex = 0; size_t endIndex = 0; while (true) { //FIND WORDS pair<size_t, size_t> iPair = { str.find("<invoke ", startIndex), str.find("</invoke>", endIndex) }; //COUNTS if (iPair.first != -1) sizePair.first++; if (iPair.second != -1) sizePair.second++; //IF IT MEANS THE START, if (indexPair.get() != nullptr && sizePair.first == 0) { //SPECIFY THE STARTING INDEX indexPair.reset(new pair<size_t, size_t>(iPair.first, string::npos)); } //FAILED TO FIND NOTHING if(iPair.first == string::npos || iPair.second == string::npos) break; //AN INVOKE HAS FOUND if(indexPair.get() != nullptr && sizePair.first == sizePair.second) { //INDEX size_t start = indexPair->first; size_t end = indexPair->second + string("</invoke>").size(); //CONSTRUCT INVOKE shared_ptr<XML> xml(new XML(str.substr(start, end - start))); shared_ptr<Invoke> invoke(new Invoke()); invoke->construct(xml); invokeList.push_back(invoke); //CLEAR CURRENT INEX PAIR endIndex = end; indexPair.reset(nullptr); } //ADJUST INDEX startIndex = (iPair.second == string::npos) ? iPair.first + 1 : iPair.second + 1; } //ERASE USED CHARACTERS if (endIndex != string::npos) str = str.substr(endIndex);*/ if (invokeList.empty() == true) return; /*str = str.substr(endIndex); cout << "#" << invokeList.size() << endl;*/ // CUT USED STRING str = move(str.substr(str.rfind("</invoke>") + CLOSED_PARENTHESIS)); //CALL REPLY_DATA auto last_it = --invokeList.end(); for (auto it = invokeList.begin(); it != last_it; it++) _replyData(*it); //TEST WHETHER THE LAST CONTAINS BINARY DATA shared_ptr<Invoke> &lastInvoke = *last_it; for (size_t i = 0; i < lastInvoke->size(); i++) { //IF HAS, TO HANDLE_BINARY if (lastInvoke->at(i)->getType() == "ByteArray") { baInvoke = lastInvoke; piece.setPosition ( piece.getPosition() - (pieceString.size() - (pieceString.rfind("</invoke>") + CLOSED_PARENTHESIS)) ); //HANDLING LEFT BINARY PIECE handleBinary(piece, str, baInvoke, size); return; } } //ELSE, DOES NOT HAVE, CALL REPLY_DATA _replyData(lastInvoke); }
/* ----------------------------------------------------------------------- LISTEN MESSAGE ----------------------------------------------------------------------- */ void IWebClientBase::listen() { shared_ptr<Invoke> binaryInvoke; // CLIENT ADDS MASK unsigned char mask = DIRECTION() == SERVER ? 128 : 0; while (true) { ByteArray piece; boost::system::error_code error; piece.assign(BUFFER_SIZE(), NULL); socket->read_some(boost::asio::buffer(piece), error); while (piece.getPosition() != piece.size()) { if (error) return; // GET TYPE unsigned char typeHeader = piece.read<unsigned char>(); if (piece.leftSize() == 0) continue; // GET SIZE TYPE unsigned char sizeHeader = piece.read<unsigned char>() - mask; if (piece.leftSize() == 0) continue; // GET SIZE size_t size = 125; if (sizeHeader == 126) { if (piece.leftSize() < sizeof(unsigned short)) listenMoreBytes(piece, error); if (error) break; size = (size_t)piece.readReversely<unsigned short>(); } else if (sizeHeader == 127) { if (piece.leftSize() < sizeof(unsigned long long)) listenMoreBytes(piece, error); if (error) break; size = (size_t)piece.readReversely<unsigned long long>(); } // GET DATA FOLLOWING TYPE if (typeHeader == (unsigned char)129) binaryInvoke = listenString(size, piece, error); else if (typeHeader == (unsigned char)130 && binaryInvoke != nullptr) listenBinary(size, piece, binaryInvoke, error); else break; } } }
//多客户端拼包和粘包不知道怎么处理。以后解决。 int Work::recvSocket(int fd) { ByteArray ba; int ret = 0; int recvSize = -1; unsigned int totalRecv = 0; do { recvSize = recv(fd, ba.buf, sizeof(ba.buf), 0); cout << "recvSize:: "<<recvSize<<endl; if(recvSize > 0) { totalRecv += recvSize; } ba.setBytesAvailable(totalRecv); ba.setBufLen(totalRecv); }while(recvSize > 0); //假如消息是从头开始接收的 //假如不足四个字节 则不知道怎么处理,所以先要缓存起来 cout<< "total:: "<<ba.getBufLen()<<endl; if(ba.getBufLen() >= 4)//取得消息头和消息长度 等于4的时候是空消息 { len = ba.readUnsignedShort();//取得长度 cout<<"len:: "<<len<<endl; head = ba.readUnsignedShort();//取得协议号 cout<<"head:: "<<head<<endl; if( ba.getBufLen() >= len )//包含了至少一条完整的消息 { cout<<"position is: "<<ba.getPosition() << " available is: "<<ba.getBytesAvailable() << endl; handleMsg(head, ba, fd); } } if(recvSize < 0) { if(errno == EINTR)//还要继续再读 { cout<<"ERRNO IS EINTR"<<endl; ret = 1; } else if(errno == EAGAIN) { cout<<"ERRNO IS EINTR"<<endl; ret = 1; } else { cout<<"socket listen failed ! " << strerror(errno) << endl; ret = - 1; } } else if(recvSize == 0)//正常退出 { cout<<"socket closed failed ! " << strerror(errno) << endl; ret = 0; } else { ret = 1; } return ret; }