可变大小的缓冲区,用于接收UDP数据包 [英] Variable-size buffer for receiving UDP packets

查看:163
本文介绍了可变大小的缓冲区,用于接收UDP数据包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an UDP socket that will receive some packets, of potentially different sizes, and I handle this asynchronously:

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

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

The problem here is that to handle the different sizes I have a big buffer, something that could be addressed with variable size buffers.

据我所知,使用async_receive_from时,一次仅使用一个数据包调用该处理程序,因为数据包边界保留在UDP中.因此,是否可以为async_receive_from提供一个空缓冲区,以便Asio可以增长以适合数据包大小?

To my understanding, when using async_receive_from, the handler is called with only one packet at a time, because the packet boundaries are preserved in UDP. So, is there a way to give an empty buffer to async_receive_from that Asio will grow to fit the packet size ?

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

Also note that I wrap packets, so for every packet transiting to this socket, the 4 first bytes are the length of the packet.

推荐答案

要获得更精确的答案,请参见以下详细说明的代码.

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

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

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);
}

现在,当接收到数据包时,将调用receive_handler而不填充任何缓冲区.

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

现在,对于处理程序:

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数据包,这也是我的计算机可以处理的最大数据包).

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];

这里发生了神奇的事情:真正的"接收调用在这里完成,并且通常会很快,因为它只会填充缓冲区.此调用将仅使一个数据包出队(即使在调用时套接字中有多个).返回值在这里很重要,因为可能只有缓冲区的一部分被填满了.例如: available = 50,packetSize = 13 .

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();
}

这篇关于可变大小的缓冲区,用于接收UDP数据包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆