Receiving UDP in Java without dropping packets

▼魔方 西西 提交于 2019-12-13 07:10:07

问题


I have a library which I need to improve since it is dropping to many packets. I want to receive a RTP-Stream, but the streamer is sending bursts of 30-40 packets within a millisecond (MJPEG-Stream). I can see the packets being complete when monitoring traffic in Wireshark. But when trying to receive them in Java, I lose a lot of those packets.

I have already been able to improve the libraries behavior by implementing a ring buffer that would constantly get filled whenever a packet is available and a separate reader thread that reads from this buffer. But I'm still not able to get all the packets from my socket that I can see in wireshark. Through RTP sequence numbers I can monitor in the reader thread if the packet processed is the one expected.

The following code is handling packet receiving:

private volatile byte[][] packetBuffer = new byte[1500][BUFFER_SIZE];
private volatile DatagramPacket[] packets = new DatagramPacket[BUFFER_SIZE];
private volatile int writePointer = 0;

public void run() {
    Thread reader = new RTPReaderThread();
    reader.start();

    while (!rtpSession.endSession) {

        // Prepare a packet
        packetBuffer[writePointer] = new byte[1500];
        DatagramPacket packet = new DatagramPacket(packetBuffer[writePointer], packetBuffer[writePointer].length);

        // Wait for it to arrive
        if (!rtpSession.mcSession) {
            // Unicast
            try {
                rtpSession.rtpSock.receive(packet);
            } catch (IOException e) {
                if (!rtpSession.endSession) {
                    e.printStackTrace();
                } else {
                    continue;
                }
            }
        } else {
            // Multicast
            try {
                rtpSession.rtpMCSock.receive(packet);
            } catch (IOException e) {
                if (!rtpSession.endSession) {
                    e.printStackTrace();
                } else {
                    continue;
                }
            }
        }
        packets[writePointer] = packet;

        this.incrementWritePointer();           
        synchronized (reader) {
            reader.notify();
        }
    }
}

What I already know:

  • I know that UDP is allowed to lose packets, but I still want to achieve the best possible result. If wireshark can see the packet, I want to be able to retrieve it as well, if possible.
  • I know that the ring buffer is never full while losing packets, so this doesn't make me lose packets either. I tried with BUFFER_SIZES of 100 and even 1000, but I already lose the first packets before a total of 1000 packets has been send.

So the question is: what is best practice to receive as many packets as possible from a DatagramSocket? Can I improve handling of packet bursts?


回答1:


Try setting the SO_RCVBUF size on the datagram socket with rtpSock.setReceiveBufferSize(size). This is only a suggestion to the OS, and the OS may not honor it, especially if it is too large. But I would try setting it to (SIZE_OF_PACKET * 30 * 100), where 30 is for the number of packets in a burst, and 100 is a guess of the number of milliseconds where you will not be able to keep up with the arrival speed.

Note that if your code cannot keep up with processing at the arrival speed in general, the OS has no choice but to drop packets.



来源:https://stackoverflow.com/questions/20213953/receiving-udp-in-java-without-dropping-packets

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!