我有一个UDP套接字,它将接收一些可能不同大小的数据包,我会异步处理它:
socket.async_receive_from(boost::asio::buffer(buffer, 65536), senderEndpoint, handler);
这里的问题是,为了处理不同的大小,我有一个很大的缓冲区,可以通过可变大小的缓冲区来解决.
据我所知,在使用时async_receive_from
,一次只调用一个数据包,因为数据包边界在UDP中保留.那么,有没有办法给空缓冲区async_receive_from
,Asio会增长到适合数据包大小?
另请注意,我包装了数据包,因此对于每个传输到此套接字的数据包,4个第一个字节是数据包的长度.
有关更精确的答案,请参阅详细说明的代码.
首先,我们需要在不填充缓冲区的情况下调用接收处理程序.这是使用boost::asio::null_buffer()
(参见反应堆式操作以获取更多信息,如Tanner所述).
void UDPConnection::receive() { socket.async_receive(boost::asio::null_buffers(), receive_handler); }
现在,当收到一个数据包时,receive_handler
将调用没有任何缓冲区来填充.
现在,对于处理程序:
void UDPConnection::handleReceive(const boost::system::error_code& error, unsigned int) { // Standard check: avoid processing anything if operation was canceled // Usually happens when closing the socket if(error == boost::asio::error::operation_aborted) return;
有了socket.available()
,我们可以得到要读取的字节数.重要提示:此数字不一定是数据包的大小!对于我的测试,这个数字总是大于数据包大小(即使是8 kB数据包,这是我的计算机可以处理的最大数据包).
// Prepare buffer unsigned int available = socket.available(); unsigned char* buffer = new unsigned char[available];
魔术发生在这里:"真正的"接收呼叫在这里完成,并且通常会很快,因为它只会填充一个缓冲区.此调用只会使一个数据包出列(即使在调用时,套接字中有多个数据包).返回值在这里很重要,因为只有缓冲区的一部分可能已被填充.例如:可用= 50,packetSize = 13.
// Fill it boost::asio::ip::udp::endpoint senderEndpoint; boost::system::error_code ec; unsigned int packetSize = socket.receive_from(boost::asio::buffer(buffer, available), senderEndpoint, 0, ec);
现在,只是标准的错误检查/处理/等...
if(ec) { // ... } // Process packet // ... receive(); }