在Java中接收UDP而不丢弃数据包

时间:2013-11-26 10:08:33

标签: java sockets networking rtp datagram

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

我已经能够通过实现一个环形缓冲区来改善库的行为,无论何时数据包可用以及从该缓冲区读取的单独读取器线程,环形缓冲区都会不断填充。但我仍然无法从Wirehark中看到我的套接字中的所有数据包。通过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接收尽可能多的数据包的最佳做法是什么?我可以改进数据包突发的处理吗?

1 个答案:

答案 0 :(得分:3)

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

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