C ++ Boost asio获取数据大小?

时间:2014-03-07 16:46:36

标签: c++ boost boost-asio

我正在使用boost asio库来使用tcp读取一些数据。使用a.accept(*sock);后,如何获取客户端将发送的第一个数据包的大小?

我使用(sock->remote_endpoint().address()).to_string()来获取用户的IP地址,所以我想必须有类似的简单方法来获取数据包的大小,对吧?

1 个答案:

答案 0 :(得分:4)

在应用程序级别,知道当前可用于读取的字节数通常更有用,而不是数据包大小。可用于读取的数据量可以从一个或多个TCP 构建。在OSI model中,TCP (第4层:传输)可以从一个或多个IP层数据包(第3层:网络)构建,每个数据包可以由一个或多个以太网(第2层:数据链路)构建。

因此,我将假设应用程序有兴趣知道要读取多少字节,而不是知道较低级别的详细信息,例如数据包的大小。这个问题有几个解决方案:

  • 通过socket::available()查询套接字可用的数据量,然后相应地分配缓冲区。

    std::vector<char> data(socket_.available());
    boost::asio::read(socket_, boost::asio::buffer(data));
    
  • 使用Boost.Asio可以在内存中增长的类,例如boost::asio::streambuf。某些操作(例如boost::asio::read()接受streambuf个对象作为其缓冲区,并将按操作所需的内容分配内存。但是,应提供完成条件;否则,操作将继续,直到缓冲区已满。

    boost::asio::streambuf data;
    boost::asio::read(socket_, data,
                      boost::asio::transfer_at_least(socket_.available()));
    
  • 正如Igor R.在评论中建议的那样,将长度作为通信协议的一部分。检查Boost.Asio examples以获取通信协议的示例。专注于协议,不一定在Boost.Asio API上。

    • 在固定长度协议中,常量字节大小用于指示消息边界,例如Boost.Asio Porthopper示例。当读者知道消息的大小时,读者可以提前分配缓冲区。
    • 在可变长度协议中,例如Boost.Asio Chat示例中使用的协议,消息通常分为两部分:标题和正文。一种方法是具有固定大小的头部,其包含各种元信息,例如身体的长度。这允许应用程序将标头读入固定大小的缓冲区,提取体长,为正文分配缓冲区,然后读取正文。

      // Read fixed header.
      std::vector<char> data(fixed_header_size);
      boost::asio::read(socket_, boost::asio::buffer(data));
      
      protocol::header header(data);
      network_to_local(header); // Handle endianess.
      
      // Read body.
      data.resize(header.body_length());
      boost::asio::read(socket_, boost::asio::buffer(data));  
      
      protocol::body body(data);
      network_to_local(body); // Handle endianess.
      

另一方面,如果我弄错了,你确实需要total length的数据包,那么可以使用basic_raw_socket。 Boost.Asio的ICMP example演示了从套接字读取IPv4数据包,并提取标头的字段值。