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

时间:2017-07-05 15:23:27

标签: c++ networking boost-asio wireshark

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

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

我的问题:WireShark是否有可能获得我的应用程序没有的数据包?我想也许WireShark可以对IP堆栈进行低级访问,即使它们在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;
}

3 个答案:

答案 0 :(得分:4)

  

这可能是WireShark获取数据包和我的应用程序   不是吗?

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

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

答案 1 :(得分:1)

数据包中有多少字节?你将缓冲区设为64K,大小为32K。那么3.5k * 32k意味着112MB / s,我不认为千兆网络可以承受它。并且,您将数据包写入文件,sputn可能阻止您接收更多数据包,因此驱动程序的缓冲区溢出,数据包被丢弃。

答案 2 :(得分:1)

总之,是的。

如果你想修复改进这个,而不是仅仅询问它,使用更大的套接字接收缓冲区而不是默认值,与平台允许的一样大,并确保您对该文件的写入也是缓冲的,只要您能提供足够大的缓冲区,无论您对崩溃时数据丢失的要求如何。