Variable-size buffer for receiving UDP packets

落爺英雄遲暮 提交于 2019-12-03 08:57:12

For a more precise answer, here is a detailed and explained code.

First, we need to call the receive handler without filling a buffer. This is done using boost::asio::null_buffer() (see reactor-style operations for more information, as stated by Tanner).

void UDPConnection::receive()
{
    socket.async_receive(boost::asio::null_buffers(), receive_handler);
}

Now, when a packet will be received, receive_handler will be called without any buffer to be filled.

Now, for the 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;

With socket.available(), we can get the number of bytes to be read. Important: this number is not necessarily the size of the packet! For my tests, this number was always greater than the packet size (even with 8 kB packets, which was the largest my computer could handle).

    // Prepare buffer
    unsigned int available = socket.available();
    unsigned char* buffer = new unsigned char[available];

Here the magic happens: the "real" receive call is done here, and will normally be fast, since it will just fill a buffer. This call will only dequeue one packet (even if at the time of the call there was more than one in the socket). The return value is important here, as only a part of the buffer may have been filled. Ex: 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);

Now, just standard error-checking / processing / etc...

    if(ec)
    {
        // ...
    }

    // Process packet
    // ...
    receive();
}

You could do that by hand. my_socket.available() returns the size of the next Udp packet waiting in line at the socket to be read. So you could use that to check how big the next packet is, grow your buffer accordingly and then receive it. However, i agree with the comenters that that is most likely less efficient than just using the biggest possible size as buffer. Unless maybe the maximum is a lot larger than the average packet and is so unlikely that your app will often not have to receive it at all.

But that is a question for optimization. The answer to your question is available() and growing the buffer yourself.

edit: I am aware that this is less than ideal in an async situation as available() only returns the size of the next udp packet if it is already waiting when available() is called.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!