我有使用Boost.Asio和SSL的客户端 - 服务器应用程序。服务器有很多线程。服务器使用async_read
,有时我会使用bytes_received != bytes_expected
和ec == 0
调用异步处理程序。大多数时候应用程序错过了2048-16384字节中的1-500个字节(应用程序中通常的逻辑数据包大小)。
我的问题与此类似 - Why boost::asio::async_read completion sometimes executed with bytes_transferred=0 and ec=0?。
要解决此问题,我为每个io_service::strand
制作了专用ssl::stream
,为io_service::strand
制作了一个ssl::context
(在线程之间共享)。我用io_service::strand::wrap()
(async_read,async_write,async_wait)包装了所有异步调用。常规通过io_service::strand::post()
发起。我在每次调用套接字方法(io_service::strand::running_in_this_thread()
)之前都进行了调试检查。但是我还有破包......
由于在处理async_read
/ async_write
Boost期间此答案https://stackoverflow.com/a/12801042/1802974,所以.Asio可以使intermediate handlers
必须在链内。这是解决这个奇怪问题的最后机会。如何检查所有intermediate handlers
是否在专用套接字链内实际执行?
更新
经过大量调试后我发现了我的问题 - 它根本没有连接到SSL。那是因为错误操纵缓冲区......
在我的应用程序中,我使用std::vector<char>
作为缓冲区(每个套接字有两个向量 - 一个用于读取操作,一个用于写入操作)。在套接字打开后立即使用默认(零)长度创建的向量。
我有二进制协议。每个数据包由标头和有效负载组成。标头包含有效负载的长度。在服务器收到数据包的标头后,它会检查读缓冲区是否足以接收有效负载。如果缓冲区小于数据包有效负载 - 服务器会增加缓冲区。
用于管理缓冲区大小的代码(不要这样做):
if (buf.capacity() >= newSize)
{
return;
}
buf.resize(newSize);
之后我构建了这样的asio缓冲区:
boost::asio::buffer(myVector, expectedPacketLength)
即。使用了这个重载:boost.org
现在我们将看到错误:
- Client sends packet of the length 400
- Server increases size of the buffer to 400 (size == 400, capacity == 400)
- Server successfully receives packet
- Client sends packet of the length 415
- Server increases size of the buffer to 415.
But `std::vector` has its own logic to increase capacity and reallocate data.
After 'resizing' actual parameters - capacity == 800, size == 415.
- Server successfully receives packet
- Client sends packet of the length 430
- Server try to increase size of a buffer, but capacity is already bigger than 430.
Nothing is done.
- Server creates buffer.
But mentioned overload of `boost::asio::buffer` has its own logic - size of created buffer 415.
- voila, we miss 15 last bytes of the packet
为什么我在这里发帖?
小心使用缓冲区))只需使用std::vector::reserve
来增加大小并使用boost::asio::buffer
boost.org的最基本重载