0

ここに記載されている関数の 3 番目のパラメーターの実装に問題があります : http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/reference/async_read_until/overload4.htmlできることは、async_read_until の 3 番目のパラメーターでコールバックを使用して、完全なチャンクがいつ到着したかを検出することです。私のパケットは次の形式です。

  • 1 バイト ID (データの意味論的意味)
  • unsigned int (一部のデータ チャンクはサイズが変わる可能性があるため、データのバイト数)
  • ペイロード

ドキュメントのサンプル コードを見ると、開始イテレータと終了イテレータから unsigned int は言うまでもなく、バイトを抽出する方法について少し混乱しています。イテレータを次のようにインスタンス化しました typedef boost::asio::buffers_iterator< boost::asio::streambuf::const_buffers_type> iterator;

しかし、それでも const_buffers_type が何であるかがわからないため、それがどのタイプかはわかりません。ドキュメントのいくつかのリンクをたどったところ、「実装定義」であることがわかりましたが、間違っている可能性があると思います。したがって、私の2つの具体的な質問は次のとおりです。

  1. これら 2 つの反復子を使用して unsigned int を読み取るにはどうすればよいですか?
  2. これらのイテレータはどのタイプを指していますか?

ありがとう!

4

2 に答える 2

1

私はあなたのものと非常によく似たメッセージ形式を持っています (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);
    }
}
于 2010-01-03T00:09:39.713 に答える
1

サンプルの一致関数がドキュメントに記載されています。

std::pair<iterator, bool>
match_whitespace(iterator begin, iterator end)
{
  iterator i = begin;
  while (i != end)
    if (std::isspace(*i++))
      return std::make_pair(i, true);
  return std::make_pair(i, false);
}

ここで逆参照iすると、1 バイトが引き出されます。intに一致するのに十分なバイトを引き出す必要があります。

ただし、read_until のオプションはコールバックだけではないことに注意してください。実際、それは最も複雑です。代わりに正規表現を使用するだけでは不十分であると確信していますか?

template<
    typename AsyncReadStream,
    typename Allocator,
    typename ReadHandler>
void async_read_until(
    AsyncReadStream & s,
    boost::asio::basic_streambuf< Allocator > & b,
    const boost::regex & expr,
    ReadHandler handler);

とにかく、読み取りが区切られていないことを考えると、サイズを読み取るまで async_read_some を実行し、少なくとも読み取りを使用して async_read_some を実行する方がはるかに良い方法です。

于 2010-01-03T00:13:53.387 に答える