我有一个UDP套接字,它会接收一些可能不同大小的数据包,我会异步处理它:
socket.async_receive_from(boost::asio::buffer(buffer, 65536), senderEndpoint, handler);
这里的问题是,为了处理不同的大小,我有一个很大的缓冲区,可以用可变大小的缓冲区解决。
据我所知,在使用async_receive_from
时,一次只调用一个数据包,因为数据包边界在UDP中保留。那么,有没有办法给async_receive_from
一个空缓冲区,Asio会增长以适应数据包大小?
另请注意,我包装了数据包,因此对于每个传输到此套接字的数据包,第一个4个字节就是数据包的长度。
答案 0 :(得分:10)
有关更准确的答案,请参阅详细说明的代码。
首先,我们需要在不填充缓冲区的情况下调用接收处理程序。这是使用boost::asio::null_buffer()
完成的(有关详细信息,请参阅reactor-style operations,如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();
}
答案 1 :(得分:1)
你可以手动完成。
my_socket.available()
返回在要读取的套接字中排队等待的下一个Udp数据包的大小。因此,您可以使用它来检查下一个数据包的大小,相应地增大缓冲区然后接收它。但是,我同意这些评论者的意见,那就是效率低于仅使用最大可能的大小作为缓冲区。除非最大值比平均数据包大很多,否则您的应用程序根本不必接收它。
但这是一个优化问题。您的问题的答案是available()
并自己增加缓冲区。
编辑:我知道这在异步情况下不太理想,因为available()
只返回下一个udp数据包的大小,如果它在调用available()
时已经在等待。