我正在使用boost asio库来使用tcp读取一些数据。使用a.accept(*sock);
后,如何获取客户端将发送的第一个数据包的大小?
我使用(sock->remote_endpoint().address()).to_string()
来获取用户的IP地址,所以我想必须有类似的简单方法来获取数据包的大小,对吧?
答案 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 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数据包,并提取标头的字段值。