1

I am developing client-server application which transfers data via UDP. I am facing the problem of dropped packets. I added socket buffer checking to detect potential overflow. Also my app checks sequence of received numbers in packets. Packets have fixed size. If free space of socket buffer is less than threshold (size of 3 packets for example) then "Critical level of buffer" message is logged. If number of packet is skipped in sequence then corresponding message is logged. There is code:

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

Even if checking of buffer status and packet processing m_onReceive are disabled and bytesAvailable > 0 replaced with true, udp packets are dropped. Speed rate is ~71 Mb/s via 1Gb Ethernet. Windows 10 is used. Also I checked netstat -s result: no reassembly failures. Socket buffer is never being overflowed.

  • You would be better off losing the `available()` test and just looping on `receive()`, letting it block while there is no data. You're potentially doubling the number of system calls. which will slow you down dramatically. – user207421 Mar 22 '18 at 06:36
  • I tried it before. There were `receive()` and checking of sequence only. It did not help. – Денис Иовлев Mar 22 '18 at 09:05

0 Answers0