用于接收UDP数据包的可变大小缓冲区

时间:2013-12-06 08:53:29

标签: c++ boost udp buffer boost-asio

我有一个UDP套接字,它会接收一些可能不同大小的数据包,我会异步处理它:

socket.async_receive_from(boost::asio::buffer(buffer, 65536), senderEndpoint, handler);

这里的问题是,为了处理不同的大小,我有一个很大的缓冲区,可以用可变大小的缓冲区解决。

据我所知,在使用async_receive_from时,一次只调用一个数据包,因为数据包边界在UDP中保留。那么,有没有办法给async_receive_from一个空缓冲区,Asio会增长以适应数据包大小

另请注意,我包装了数据包,因此对于每个传输到此套接字的数据包,第一个4个字节就是数据包的长度。

2 个答案:

答案 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()时已经在等待。