私はあなたのものと非常によく似たメッセージ形式を持っています (16 ビットのペイロード長、8 ビットのパケット ID/タイプ、その後に私のペイロードが続きます)。私は 3 フェーズの読み取りと、さまざまなことを処理するための関数ポインターの配列でそれを行いました。boost::asio::async_read を使用して、一度に既知の量を読み取りました。
これは私のコードの簡略版です:
//call this to start reading a packet/message
void startRead(boost::asio::ip::tcp::socket &socket)
{
boost::uint8_t *header = new boost::uint8_t[3];
boost::asio::async_read(socket,boost::asio::buffer(header,3),
boost::bind(&handleReadHeader,&socket,header,
boost::asio::placeholders::bytes_transferred,boost::asio::placeholders::error));
}
void handleReadHeader(boost::asio::ip::tcp::socket *socket,
boost::uint8_t *header, size_t len, const boost::system::error_code& error)
{
if(error)
{
delete[] header;
handleReadError(error);
}
else
{
assert(len == 3);
boost::uint16_t payLoadLen = *((boost::uint16_t*)(header + 0));
boost::uint8_t type = *((boost::uint8_t*) (header + 2));
delete[] header;
//dont bother calling asio again if there is no payload
if(payLoadLen > 0)
{
boost::uint8_t *payLoad = new boost::uint8_t[payLoadLen];
boost::asio::async_read(*socket,boost::asio::buffer(payLoad,payLoadLen),
boost::bind(&handleReadBody,socket,
type,payLoad,payLoadLen,
boost::asio::placeholders::bytes_transferred,boost::asio::placeholders::error));
}
else handleReadBody(socket,type,0,0,0,boost::system::error_code());
}
}
void handleReadBody(ip::tcp::socket *socket,
boost::uint8_t type, boost::uint8_t *payLoad, boost::uint16_t len,
size_t readLen, const boost::system::error_code& error)
{
if(error)
{
delete[] payLoad;
handleReadError(error);
}
else
{
assert(len == readLen);
//passes the packet to the appropriate function for the type
//you could also use a switch statement or whatever
//to get the next packet you must call StartRead again
//personally I choose to do this from the actaul handler
//themselves
handlePacket(type,payLoad,len,error);
}
}