在 Java 中接收 UDP 而不丢包 [英] Receiving UDP in Java without dropping packets

查看:62
本文介绍了在 Java 中接收 UDP 而不丢包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个需要改进的库,因为它丢弃了很多数据包.我想接收一个 RTP-Stream,但流媒体在一毫秒内发送 30-40 个数据包的突发(MJPEG-Stream).在 Wireshark 中监控流量时,我可以看到数据包已完成.但是当我尝试用 Java 接收它们时,我丢失了很多这样的数据包.

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.

我已经能够通过实现一个环形缓冲区来改进库的行为,只要有数据包可用,该缓冲区就会不断填充,以及从该缓冲区读取的单独读取器线程.但是我仍然无法从我可以在wireshark中看到的套接字中获取所有数据包.通过 RTP 序列号,我可以在读取器线程中监控处理的数据包是否符合预期.

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

我已经知道的:

  • 我知道UDP允许丢包,但我还是想达到最好的结果.如果wireshark可以看到数据包,我如果可能,也希望能够检索到它.
  • 我知道在丢失数据包时环形缓冲区永远不会满,所以这也不会让我丢失数据包.我试过 BUFFER_SIZES100 甚至 1000,但我已经丢失了之前的第一个数据包总共发送了 1000 个数据包.

所以问题是:从 DatagramSocket 接收尽可能多的数据包的最佳实践是什么?我可以改进对数据包突发的处理吗?

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?

推荐答案

尝试使用 rtpSock.setReceiveBufferSize(size) 在数据报套接字上设置 SO_RCVBUF 大小.这只是对操作系统的一个建议,操作系统可能不会尊重它,尤其是当它太大时.但是我会尝试将其设置为 (SIZE_OF_PACKET * 30 * 100),其中 30 是突发中的数据包数量,而 100 是您将无法跟上到达速度的毫秒数的猜测.

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.

这篇关于在 Java 中接收 UDP 而不丢包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆