高频接收UDP数据包:丢包?

Receiving UDP packets at high frequency : packet loss?

我有一个 C++ 应用程序,它使用 UDP 服务器(使用 Boost.Asio),以高频率(每秒 3500 个数据包)从千兆位本地网络设备接收数据包。一些用户报告了一些数据包丢失。所以最后我选择 运行 并行 WireShark 和我的应用程序来检查是否有 WireShark 能够接收但我的应用程序不能接收的数据包。

我发现WireShark并没有收到每个数据包,似乎漏掉了一些。我的应用程序还错过了 Wireshark 正确接收的更多帧。

我的问题:WireShark 是否可能获取我的应用程序未获取的数据包?我想也许 WireShark 对 IP 堆栈具有低级访问权限,并且数据包被 OS 丢弃,即使它们显示在 WireShark 中? 是否有可能 (1) 中的操作花费了太多时间,以至于下一个 async_receive_from 被调用得太晚了? 我想就这个问题发表意见。谢谢

这是我使用的代码(非常基本)。 udp_server.h :

#pragma once

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <fstream>

const int MAX_BUFFER_SIZE = 65537;

using boost::asio::ip::udp;

class UDPServer
{
public:
    UDPServer(boost::asio::io_service& ios, udp::endpoint endpoint)
        :m_io_service(ios),
        m_udp_socket(m_io_service, endpoint)
    {
        // Resize the buffer to max size in the component property
        m_recv_buffer.resize(MAX_BUFFER_SIZE);

        m_output_file.open("out.bin", std::ios::out | std::ios::binary);

        StartReceive();
    }

public:
    void StartReceive()
    {
        m_udp_socket.async_receive_from(
            boost::asio::buffer(m_recv_buffer), m_remote_endpoint,
            boost::bind(&UDPServer::HandleReceive, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }

private:
    void HandleReceive(const boost::system::error_code& error, std::size_t bytes_transferred)
    {
        if (!error || error == boost::asio::error::message_size)
        {
            // Write to output -- (1)
            m_output_file.sputn(&m_recv_buffer[0], bytes_transferred);

            // Start to receive again
            StartReceive();
        }
    }

    boost::asio::io_service&    m_io_service;
    udp::socket                 m_udp_socket;
    udp::endpoint               m_remote_endpoint;
    std::vector<char>           m_recv_buffer;
    std::filebuf                m_output_file;
};

main.cpp:

include <boost/asio.hpp>
#include "udp_server.h"

const unsigned short PORT_NUMBER = 44444;

int main()
{
    boost::asio::io_service ios;
    boost::asio::ip::udp::endpoint endpoint(udp::endpoint(udp::v4(), PORT_NUMBER));
    UDPServer server(ios, endpoint);
    ios.run();

    return 0;
}

一个数据包有多少字节?您将缓冲区设置为 64K,让大小为 32K。然后 3.5k * 32k 表示 112MB/s,我认为千兆网络负担不起。并且,你将数据包写入文件,sputn 可能会阻止你接收更多的数据包,因此驱动程序的缓冲区溢出,数据包被丢弃。

Is this possible that WireShark get a packet and that my application does not ?

是的。特别是,每个套接字都有自己的固定大小的传入数据缓冲区,如果此时内核试图将新的传入数据包添加到该缓冲区,则缓冲区没有足够的可用 space 来容纳该数据包,则该数据包将不会添加到缓冲区,因此从该套接字读取传入数据的应用程序将不会收到它。

鉴于此,WireShark 的缓冲区完全有可能有空间来接受传入的数据包,但您自己的应用程序的缓冲区却没有。

一句话,是的

如果你想修复改进这个问题,与其只是询问,不如使用much 比默认设置更大的套接字接收缓冲区,与平台允许的一样大,并确保您对文件的写入也被缓冲,无论您对数据丢失的要求如何,都可以提供尽可能大的缓冲区崩溃。