对于需要从服务器接收可变长度消息的客户端(Windows 10,Visual C++),我使用boost :: asio。 消息非常频繁(每秒超过10条消息),每条消息约为40-100字节。在Windows中使用boost :: asio优化缓冲区大小
我以这种方式使用streambuf
与async_read_some
:
void Client::readStart(void)
{
boost::asio::streambuf::mutable_buffers_type buf = _inbox.prepare(std::max((size_t)1024, _socket->available()));
// Start an asynchronous read and call readHandler when it completes or fails
_socket->async_read_some(buf,
boost::bind(&Client::readHandler,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
即我试图用_inbox.prepare(std::max((size_t)1024, _socket->available()))
动态调整缓冲区大小,以使用更大的缓冲区,当许多消息都积累了,因为客户端仍处理先前的消息。
我发现我不能简单地总是使用像_inbox.prepare(262144)
这样的更大的缓冲区,因为readHandler
被大块数据调用,而不是更频繁。
即使尝试动态分配缓冲区,我也会遇到奇怪的延迟和数据累积。
这是我的日志:
2017-05-09 09:02:25 <debug> Received 1024 bytes
2017-05-09 09:02:25 <debug> Received 372 bytes
2017-05-09 09:02:25 <debug> Received 844 bytes
2017-05-09 09:02:25 <debug> Received 169 bytes
2017-05-09 09:02:25 <debug> Received 1024 bytes
2017-05-09 09:02:25 <debug> Received 379 bytes
2017-05-09 09:02:25 <debug> Received 1385 bytes
2017-05-09 09:02:25 <debug> Received 1421 bytes
2017-05-09 09:02:25 <debug> Received 108 bytes
2017-05-09 09:02:25 <debug> Received 1024 bytes
2017-05-09 09:02:25 <debug> Received 1768 bytes
2017-05-09 09:02:27 <debug> Received 65536 bytes
2017-05-09 09:02:33 <debug> Received 65536 bytes
2017-05-09 09:02:40 <debug> Received 65536 bytes
2017-05-09 09:02:47 <debug> Received 65536 bytes
2017-05-09 09:02:55 <debug> Received 65536 bytes
2017-05-09 09:03:01 <debug> Received 65536 bytes
2017-05-09 09:03:07 <debug> Received 65536 bytes
2017-05-09 09:03:15 <debug> Received 65536 bytes
2017-05-09 09:03:35 <debug> Received 65536 bytes
2017-05-09 09:03:41 <debug> Received 65536 bytes
2017-05-09 09:03:46 <debug> Received 65536 bytes
2017-05-09 09:03:50 <debug> Received 65536 bytes
2017-05-09 09:03:58 <debug> Received 65536 bytes
2017-05-09 09:04:02 <debug> Received 65536 bytes
2017-05-09 09:04:11 <info> Disconnected by remote host
正如你所看到的,直到9时02分25秒一切正常,那么数据开始积累和readHandler
得到很少被调用(每次调用之间7-8秒)与大块数据(65536字节)。
最后,远程主机断开连接。断开连接是由服务器发送给我的客户端的TCP ZeroWindow探测器(用Wireshark跟踪),即我的TCP缓冲区已满。
我真的不明白为什么readHandler
被称为非常不常见,并有这么多的数据(我敢肯定它不是客户端的100%CPU的问题:客户端快速处理消息和CPU负载很小)。
编辑:
我禁用此代码插槽上Nagle算法:
boost::system::error_code error;
_socket->set_option(tcp::no_delay(true), error);
在试图阻止TCP/IP堆栈从分组数据包,但它不没有帮助。
编辑2:
似乎是有瓶颈的地方在我的处理代码,所以我没有真正接收数据的速度不够快和服务器的Nagle算法中产生由以下R. Joiny描述的问题。
您可以识别Wireshark中的每个发送的以太网包吗?也许发送网络缓冲区决定将它们放在一个以太网包中,所以你的读取处理程序被调用的次数减少,但有更多的数据。我不确定,因为这通常只会以非常高的发送速率出现,但要检查这不会造成影响 –
由于路径MTU,以太网等,您永远不会获得大于1500字节的入站TCP段。 – EJP
@ R.Joiny 65536字节不能位于单个以太网数据包中,EJP是正确的。其他地方一定有问题。在任何情况下,我都会尝试更好地分析Wireshark跟踪,如果发现任何相关的问题,请更新问题。 –