简体   繁体   English

以高频率接收UDP数据包:数据包丢失?

[英]Receiving UDP packets at high frequency : packet loss?

I have a C++ application which uses a UDP Server (using Boost.Asio) that receives packets from a gigabit local network device at a high frequency (3500 packets per second). 我有一个C ++应用程序,它使用UDP服务器(使用Boost.Asio)以高频率(每秒3500个数据包)接收来自千兆位本地网络设备的数据包。 Some users report a few packet losses. 一些用户报告了一些数据包丢失。 So in the end I chose to run in parallel WireShark and my application to check if there are any packets that WireShark is able to receive but not my application. 所以最后我选择并行运行WireShark和我的应用程序来检查是否有WireShark能够接收的数据包而不是我的应用程序。

What I found is that WireShark does not receive every packet, it seems that it misses some. 我发现WireShark没有收到每个数据包,似乎它错过了一些。 My application misses also a few more frames that Wireshark received correctly. 我的应用程序还错过了Wireshark正确接收的一些帧。

My questions : Is it possible WireShark gets packets that my application does not ? 我的问题 :WireShark是否有可能获得我的应用程序没有的数据包? I thought maybe WireShark has low-level access to the IP stack and packets are discarded by the OS even if they are shown in WireShark ? 我想也许WireShark可以对IP堆栈进行低级访问,即使它们在WireShark中显示,操作系统也会丢弃数据包? Is it possible that the operation in (1) takes too much time such that the next async_receive_from is called too late? 是否有可能(1)中的操作花费太多时间,以至于下一个async_receive_from被调用太晚了? I would like to have opinions on this subject. 我想对这个问题有意见。 Thanks. 谢谢。

Here is the code I use (quite basic). 这是我使用的代码(非常基本)。 udp_server.h : 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: 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;
}

Is this possible that WireShark get a packet and that my application does not ? 这可能是WireShark得到一个数据包而我的应用程序没有?

Yes. 是。 In particular, each socket has its own fixed-size incoming-data buffer, and if, at the moment the kernel tries to add the new incoming packet to that buffer, the buffer doesn't have enough available space to hold that packet, then the packet will not be added to the buffer, and so the application reading incoming data from that socket will not receive it. 特别是,每个套接字都有自己的固定大小的传入数据缓冲区,如果内核尝试将新的传入数据包添加到该缓冲区,则缓冲区没有足够的可用空间来容纳该数据包,数据包不会被添加到缓冲区,因此从该套接字读取传入数据的应用程序将不会接收它。

Given that, it's entirely possible that WireShark's buffer had room to accept the incoming packet, but your own app's buffer did not. 鉴于此,WireShark的缓冲区完全有可能接受传入的数据包,但您自己的应用程序的缓冲区却没有。

How much bytes in a packet? 数据包中有多少字节? You make a buffer as 64K, let the size be 32K. 你将缓冲区设为64K,大小为32K。 Then 3.5k * 32k means 112MB/s, I don't think a gigabit network afford it. 然后3.5k * 32k意味着112MB / s,我不认为千兆网络可以承受它。 And, you write packets to a file, the sputn may block you from receiving more packets, consequently the buffer of the driver overflowed, packets discarded. 并且,您将数据包写入文件, sputn可能阻止您接收更多数据包,因此驱动程序的缓冲区溢出,数据包被丢弃。

In a word, yes. 总之,是的。

If you want to fix or improve this, rather than just ask about it, use a much bigger socket receive buffer than the default, as big as the platform will allow, and make sure your writes to the file are also buffered, with as large a buffer as you can afford given whatever your requirements are about data loss on crash. 如果要修复改善这一点,而不是只问它,使用一个更大的套接字接收缓冲区比默认情况下,大如该平台将允许,并确保你写入文件也被缓冲,以大根据您对崩溃时数据丢失的要求,您可以提供一个缓冲区。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM