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

Syn*_*xis 3 c++ buffer boost udp boost-asio

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

socket.async_receive_from(boost::asio::buffer(buffer, 65536), senderEndpoint, handler);
Run Code Online (Sandbox Code Playgroud)

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

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

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

Syn*_*xis 10

有关更精确的答案,请参阅详细说明的代码.

首先,我们需要在不填充缓冲区的情况下调用接收处理程序.这是使用boost::asio::null_buffer()(参见反应堆式操作以获取更多信息,如Tanner所述).

void UDPConnection::receive()
{
    socket.async_receive(boost::asio::null_buffers(), receive_handler);
}
Run Code Online (Sandbox Code Playgroud)

现在,当收到一个数据包时,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;
Run Code Online (Sandbox Code Playgroud)

有了socket.available(),我们可以得到要读取的字节数.重要提示:此数字不一定是数据包的大小!对于我的测试,这个数字总是大于数据包大小(即使是8 kB数据包,这是我的计算机可以处理的最大数据包).

    // Prepare buffer
    unsigned int available = socket.available();
    unsigned char* buffer = new unsigned char[available];
Run Code Online (Sandbox Code Playgroud)

魔术发生在这里:"真正的"接收呼叫在这里完成,并且通常会很快,因为它只会填充一个缓冲区.此调用只会使一个数据包出列(即使在调用时,套接字中有多个数据包).返回值在这里很重要,因为只有缓冲区的一部分可能已被填充.例如:可用= 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);
Run Code Online (Sandbox Code Playgroud)

现在,只是标准的错误检查/处理/等...

    if(ec)
    {
        // ...
    }

    // Process packet
    // ...
    receive();
}
Run Code Online (Sandbox Code Playgroud)