0

我无法在此处记录的函数中实现第三个参数:http: //www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/reference/async_read_until/overload4.html 我想要什么能够做的是使用 async_read_until 的第三个参数上的回调来检测完整块何时到达。我的数据包具有以下格式。

  • 1字节id(数据的语义)
  • unsigned int(数据中的字节数,因为某些数据块可以改变大小)
  • 有效载荷

查看文档中的示例代码,我有点困惑我应该如何提取一个字节,更不用说从开始和结束迭代器中提取一个无符号整数了。我已经将我的迭代器实例化为 typedef boost::asio::buffers_iterator< boost::asio::streambuf::const_buffers_type> iterator;

但即便如此我也不确定那是什么类型,因为我不知道 const_buffers_type 是什么。我关注了文档中的一些链接,发现它是“实现定义的”,但我想我可能是错的。所以我的两个具体问题是:

  1. 如何使用这两个迭代器来读取无符号整数?
  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,拉出一个字节。您需要提取足够的字节来匹配一个 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 回答