1

我正在开发通过 UDP 传输数据的客户端-服务器应用程序。我正面临丢包的问题。我添加了套接字缓冲区检查以检测潜在的溢出。我的应用程序还检查数据包中接收到的数字序列。数据包具有固定大小。如果套接字缓冲区的可用空间小于阈值(例如 3 个数据包的大小),则记录“缓冲区的关键级别”消息。如果按顺序跳过数据包的数量,则记录相应的消息。有代码:

    UdpServer::UdpServer(asio::io_service& io, uint16_t port, uint32_t packetSize) : CommunicationBase(io, port),
    m_socket(io, asio::ip::udp::endpoint(asio::ip::address_v6::any(), m_port))
    {
        m_buffer = new uint8_t[packetSize];
        m_packetSize = packetSize;
        m_socketBufferSize = m_packetSize * 32;
        m_criticalLevel = 5 * m_packetSize;

        asio::ip::udp::socket::receive_buffer_size recieveBuffSize(m_socketBufferSize);
        m_socket.set_option(recieveBuffSize);
    }

    UdpServer::~UdpServer()
    {
        std::free(m_buffer);
    }


    void UdpServer::StartReceive(std::function<void(uint8_t* buffer, uint32_t bytesCount)> receiveHandler)
    {
        m_onReceive = receiveHandler;

        Receive();
    }

    inline void UdpServer::Receive()
    {
        m_socket.async_receive(asio::null_buffers(), [=](const boost::system::error_code& error, size_t bytesCount)
        {
            OnReceive(bytesCount, error);
        });
    }

    void UdpServer::OnReceive(size_t bytesCount, const boost::system::error_code& error)
    {
        static uint16_t lastSendNum = 65535;
        uint16_t currentNum = 0;
        uint16_t diff = 0;

        if (error)
        {
            if (error == asio::error::operation_aborted)
            {
                logtrace << "UDP socket reports operation aborted, terminating";
                return;
            }

            logerror << "UDP socket error (ignoring): " << error.message();
        }
        else
        {
            asio::ip::udp::endpoint from;
            boost::system::error_code receiveError;
            size_t bytesRead = 0;

            size_t bytesAvailable = m_socket.available();

            while (bytesAvailable > 0)
            {
                if (m_socketBufferSize - bytesAvailable < m_criticalLevel)
                {
                    logwarning << "Critical buffer level!";
                }

                bytesRead = m_socket.receive(asio::buffer(m_buffer, m_packetSize), 0, receiveError);

                if (receiveError)
                {
                    logerror << "UDP socket error: " << receiveError.message();

                    break;
                }

                currentNum = *reinterpret_cast<uint16_t*>(m_buffer);
                diff = currentNum - lastSendNum;

                if (diff != 1)
                {
                    logdebug << "Chunk skipped: " << diff << ". Last " << lastSendNum << " next " << currentNum;
                }

                lastSendNum = currentNum;

                if (m_onReceive)
                {
                    m_onReceive(m_buffer, bytesRead);
                }

                bytesAvailable = m_socket.available();
            }
        }

        Receive();
    }

即使m_onReceive禁用检查缓冲区状态和数据包处理并bytesAvailable > 0替换为true,也会丢弃 udp 数据包。通过 1Gb 以太网,速度约为 71 Mb/s。使用 Windows 10。我还检查了netstat -s结果:没有重组失败。套接字缓冲区永远不会溢出。

4

0 回答 0