【问题标题】:Receiving UDP in Java without dropping packets在Java中接收UDP而不丢包
【发布时间】:2013-11-26 10:08:32
【问题描述】:

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

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

以下代码处理数据包接收:

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_SIZES 100 甚至 1000,但我已经丢失了之前的第一个数据包 总共发送了 1000 个数据包。

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

【问题讨论】:

    标签: java sockets networking rtp datagram


    【解决方案1】:

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

    请注意,如果您的代码通常无法以到达速度跟上处理,则操作系统别无选择,只能丢弃数据包。

    【讨论】:

    • 非常感谢,我会试试的。我可以毫不费力地跟上检索速度,只是有些数据包有时在循环尝试获取它们时已经消失了。
    • 只是进一步说明,而不是使用synchronizenotify(),创建一个java.util.concurrent.LinkedTransferQueue,并在接收线程中执行transfer()将数据包放入队列,而处理线程从同一队列执行take()。这将比同步/通知更高效。
    • 感谢提示:java.util.concurrent.LinkedTransferQueue 不幸的是必须使用 Java6 ...
    • 然后使用LinkedBlockingQueue。在几乎所有情况下,它仍将优于 synchronize/notify
    猜你喜欢
    • 1970-01-01
    • 2017-06-13
    • 1970-01-01
    • 2015-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多