【问题标题】:How to read a fix-sized packet using boost asio?如何使用 boost asio 读取固定大小的数据包?
【发布时间】:2012-02-17 21:56:24
【问题描述】:

我正在使用 boost-asio 进行同步读/写。数据以二进制格式传入,没有边界,长度信息以数据包格式编码。因此,以指定的大小读入很重要。 ip::tcp::iostream 可以吗?有人可以提供一个例子吗?谢谢。

【问题讨论】:

  • 什么意思:长度信息是以数据包格式编码的?协议框架通常是在应用程序级别完成的,我认为您会因为考虑数据包而不是数据流而感到困惑。

标签: c++ sockets boost boost-asio


【解决方案1】:

简单:

boost::asio::read(socket, buffers, boost::asio::transfer_exactly(your_fixed_size));

【讨论】:

    【解决方案2】:

    我在一个程序上工作,该程序发送不同大小的不同数据。我使用 8 字节的固定标头来编码大小,然后,我添加数据:

     enum { header_length = 8 }; //const header length
    

    我得到了大小(m_outbound_data 是一个 std::string == 一个序列化对象)

    //give header length    
    std::ostringstream header_stream
    header_stream << std::setw(header_length) //set a field padding for header  
                  << std::hex                 //set next val to hexadecimal
                  << m_data_out.m_outbound_data.size(); //write size in hexa
    
    m_data_out.m_outbound_header = header_stream.str(); //m_outbound_head == size in hexa in a std::string
    
          //m_outbound_header = [ 8 byte size ] 
          //m_outbound_data = [ serialized data ]
    
          //write all data in the std::vector and send it
          std::vector<boost::asio::const_buffer> buffer;
          buffer.push_back(boost::asio::buffer(m_data_out.m_outbound_header));
          buffer.push_back(boost::asio::buffer(m_data_out.m_outbound_data));
    

    而对于读取,您需要读取 2 次:第一次读取 8 个字节以获取大小,然后读取向量中的数据并反序列化为对象:

     struct network_data_in {   
      char m_inbound_header[header_length]; //size of data to read  
      std::vector<char> m_inbound_data; // read data    
    };
    

    我使用这个结构来获取数据,在 m_inbound_header 上调用 read 以先用大小填充缓冲区,然后在句柄中:

    //get size of data
    std::istringstream is(std::string(m_data_in.m_inbound_header, header_length));
    std::size_t m_inbound_datasize = 0;
    is >> std::hex >> m_inbound_datasize;
    m_data_in.m_inbound_data.resize(m_inbound_datasize); //resize the vector
    

    然后使用缓冲区上的 m_inbound_data 再次调用 read,此结果将准确读取发送的数据 在第二个 handle_read 中,您必须反序列化数据:

    //extract data
    std::string archive_data (&(m_data_in.m_inbound_data[0]),m_data_in.m_inbound_data.size());
    std::istringstream archive_stream(archive_data);
    boost::archive::text_iarchive archive(archive_stream);
    archive >> t; //deserialize
    

    希望对你有所帮助!

    【讨论】:

    • +1 好答案,这就是我的建议。修改您的协议以包含固定长度的标头。如果您无法修改协议,请在问题中说明。
    【解决方案3】:

    TCP 是一种基于流的协议。这意味着您读取的任何内容都只是一个字节流。 让我们考虑一个例子:你有一个固定大小的消息,你通过 TCP 发送它。另一端的程序如何读取整个消息?有两种方法,一种是用控制字符包围您的消息(例如,开始时为 STX,结束时为 ETX)。开始时,程序会丢弃 STX 之前的所有字符,然后将任何其他字符读入消息缓冲区,直到遇到 ETX。

    另一种方法是将消息长度编码在固定大小的标头中(显然是您的情况)。所以你能做的最好的事情就是找出一种方法来读取消息长度,解析它并相应地读取剩余的字节。

    【讨论】:

    • 我知道您需要长度信息,这是给定的。不清楚的是在 API 中指定这个长度(我要读取的字节数)。
    • @Oliver 您的评论没有意义。要读取的字节数在 API 中有很好的记录,例如 boost::asio::read
    • 很好的解释!不是吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-24
    • 2015-02-25
    • 2011-08-09
    相关资源
    最近更新 更多