简体   繁体   English

Java Udp套接字,数据包在本地主机中丢失

[英]Java Udp sockets, packets lost in localhost

I am implementing a simple java udp socket program. 我正在实现一个简单的Java udp套接字程序。 Here are the details: 详细信息如下:

  • Server side: suppose I create 2500 packets in server side, then inform the client that i'm gonna send 2500 packets, and each packet is packetSize bytes. 服务器端:假设我在服务器端创建了2500个数据包,然后通知客户端我将发送2500个数据包,每个数据包均为packetSize字节。 then in a loop, each packet is created and then sent. 然后在循环中,创建每个数据包,然后发送。
  • Client side: after being informed of the number of packets, in a for (or while), I wait for 2500 packets to be received. 客户端:在得知数据包数量之后,我等待了一段时间(或一段时间),然后等待2500个数据包。

Here is the problem: The for loop in client side never ends! 这是问题所在:客户端中的for循环永远不会结束! that means 2500 packets are never received! 这意味着将永远不会收到2500个数据包! Although I checked server side and it has sent them all. 虽然我检查了服务器端,并已将它们全部发送出去。

I tried setting the socket's receive buffer size to 10 * packetSize using this: 我尝试使用以下方法将套接字的接收缓冲区大小设置为10 * packetSize

socket.setReceiveBufferSize(10 * packetSize)

but it does not work. 但它不起作用。

How do you think I could solve this problem? 您认为我如何解决这个问题? I know UDP is not reliable but both client and server are running on different ports of the same computer! 我知道UDP不可靠,但是客户端和服务器都在同一台计算机的不同端口上运行!

Here is the code for server side: 这是服务器端的代码:

for (int i = 0; i < packets; i++) {
            byte[] currentPacket = new byte[size];
            byte[] seqnum = intToByteArray(i);
            currentPacket[0] = seqnum[0];
            currentPacket[1] = seqnum[1];
            currentPacket[2] = seqnum[2];
            currentPacket[3] = seqnum[3];

            for (int j = 0; j < size-4; j++) {
                currentPacket[j+4] = finFile[i][j];
            }

            sendPacket = new DatagramPacket(currentPacket, currentPacket.length, receiverIP, receiverPort);
            socket.send(sendPacket);
            try {
                Thread.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

and the client side: 和客户端:

int k = 0;
    while (true) {
        receivedBytes = new byte[size];
        receivePacket = new DatagramPacket(receivedBytes, size);
        socket.receive(receivePacket);
        allBytes.add(receivePacket.getData());
        k++;
        if (k == packets)
            break;
    }

allBytes is just a linked list containing received bytes. allBytes只是一个包含已接收字节的链表。 i use it to reassemble the final file. 我用它来重组最终文件。

PS This code works perfect for under 100Mb files. PS此代码非常适合100Mb以下的文件。 Thanks 谢谢

Update: tl;dr summary: Either packets is not properly initialized or use TCP, or add a sequence number in your UDP packet so that your client knows if it drops a packet and you can write code to handle that (request for a rebroadcast). 更新:tl; dr摘要: packets未正确初始化或未使用TCP,或在UDP数据包中添加了序列号,以便您的客户端知道它是否丢弃了数据包,并且您可以编写代码来处理该数据包(请求重播) 。 This essentially makes it a rudimentary TCP anyways. 无论如何,这本质上使其成为基本的TCP。

I have a suspicion that you never initialized packets so you never hit your break . 我怀疑您从未初始化packets因此您从未break Rewriting your while into a for loop can easily check if this is true. 将您的while重写为for循环可以轻松检查是否为真。 Assuming the first packet you send contains how many packets it will be receiving, and you initialize packets correctly then if your packets are being lost then your client side program will not end since receive() is a blocking method. 假设您发送的第一个数据包包含将要接收的数据包,并且您正确地初始化了packets ,那么如果您的数据包丢失了,您的客户端程序将不会结束,因为receive()是一种阻塞方法。

If you strongly suspect that your packets are being lost, then debug your client side and see how many received packets are in your LinkedList and compare that against how many are sent on the server side. 如果您强烈怀疑丢失了数据包,请调试客户端,查看LinkedList中有多少个接收到的数据包,并将其与服务器端发送的数据包进行比较。

for(int i = 0; i < packets; i++) {
    receivedBytes = new byte[size];
    receivePacket = new DatagramPacket(receivedBytes, size);
    socket.receive(receivePacket);
    allBytes.add(receivePacket.getData());
}
System.out.println("All " + packet + " received.");

Switching to code to the above will let you know that if you never get to the print statement, then you know that you're losing packets since receive() is a blocking method and it means that your client side is stuck in the for loop. 切换到上面的代码将使您知道,如果您从未使用过print语句,那么您就会知道丢失数据包,因为receive()是一种阻塞方法,这意味着您的客户端陷入了for循环中。 This is because the for loop can't be satisfied since if the server sends 2500 packets but the client only receives 2300 packets, it'll still be in the for loop at the receive() line waiting for 2301, 2302, ... packets and so on. 这是因为无法满足for循环的需要,因为如果服务器发送了2500个数据包,但客户端仅接收了2300个数据包,则它仍将在receive()行的for循环中等待2301、2302,...数据包等。

Since you have a file with upwards of 100MB or more that needs to be assembled I assume you can't tolerate loss, so either use TCP that will fulfill that requirement or handle that possibility in your code by creating your own header with each packet. 由于您需要组装的文件大于或等于100MB,我假设您无法承受丢失,因此请使用可以满足该要求的TCP,或者通过在每个数据包中创建自己的标头来处理这种可能性。 This header can be as simple as an incrementing sequence number that the client will receive and read, if it skips a number from the previous packet then it will know that a packet was lost. 该报头可以像客户端将要接收和读取的递增序号一样简单,如果它跳过前一个数据包中的数字,则它将知道一个数据包丢失了。 At this point, you can have your client request the server to rebroadcast that specific packet. 此时,您可以让客户端请求服务器重新广播该特定数据包。 But at this point you just implemented your own crude TCP. 但是,此时您仅实现了自己的原始TCP。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM