简体   繁体   English

Android可以发送udp但不能接收

[英]Android can send udp but not receive

I've written a basic udp client server where one android sends message to the server and server relays it to the rest of the clients. 我已经编写了一个基本的udp客户端服务器,其中一个android将消息发送到服务器,服务器将其中继到其他客户端。

The issue is, the incoming udp messages get to the server and server relays them back but they never reach the rest of the devices. 问题是,传入的udp消息到达服务器,服务器将它们中继回去,但它们从未到达其余设备。

Whats really amazing is that if I use the server as echo server (ie relaying only to sender) then everything works. 真正令人惊奇的是,如果我将服务器用作回显服务器(即仅中继到发件人),则一切正常。 All client and server sockets use same port 2706 所有客户端和服务器套接字都使用相同的端口2706

Server code 服务器代码

while (true) {
    DatagramPacket packetToReceive = new DatagramPacket(new byte[2048], 2048);
    try {
        listenerSocket.receive(packetToReceive);
        InetAddress senderAddress = packetToReceive.getAddress();
        relayedBytes += packetToReceive.getLength();

        if (!connectedClients.contains(senderAddress)) {
            connectedClients.add(senderAddress);
        }

        for (InetAddress addr : connectedClients) {
            // commenting this line will make it an echo server
            if (!addr.equals(senderAddress))
            {
                //The following actually prints the ips of the android
                //devices so it knows where to send

                System.out.println(senderAddress.getHostAddress().toString() +
                    " to " + addr.getHostAddress().toString());
                byte[] data = packetToReceive.getData();
                packetToReceive.setData(data, 0, packetToReceive.getLength());
                packetToReceive.setAddress(addr);
                listenerSocket.send(packetToReceive);
            }
        }
    } catch (IOException) {
        e.printStackTrace();
    }
}

android sender logic: android sender逻辑:

mainSocket=new DatagramSocket(homePort);

//targetAddressString is the public IP of server
target = InetAddress.getByName(targetAddressString);
while (true) {
    byte[] data = getdata();
    if (data == null)
        continue;
    DatagramPacket packet = new DatagramPacket(data, data.length, target, targetPort);

    mainSocket.send(packet);
}

meanwhile on other thread the reciever just waits with the same udp socket: 同时,在其他线程上,接收方仅使用相同的udp套接字等待:

while (true) {
    Log.d("Player", "Waiting for data");
    DatagramPacket packet = new DatagramPacket(new byte[2048], 2048);
    try {
        mainSocket.receive(packet);
        Log.d("Player", "packet received");
        //do something with the packet
    } catch (IOException e) {
        e.printStackTrace();
    }
}

It never moves further than waiting for data since it'll block until it receives a packet 它永远不会等待数据,因为它会阻塞直到收到数据包

Moreover I can also see it in the wifi and Mobile data icons that no data is ever received but data sending is always on and is seen received on the server 此外,我还可以在wifi和“移动数据”图标中看到它,从未接收到任何数据,但是数据发送始终处于打开状态,并且可以在服务器上看到接收到的数据。

**EDIT:- Echo server ** **编辑:-回声服务器**

while (true) {
    DatagramPacket receivedPacket = new DatagramPacket(new byte[2048], 2048);
    try {
        listenerSocket.receive(receivedPacket);
        InetAddress senderAddress = receivedPacket.getAddress();
        if (!connectedClients.contains(senderAddress)) {
            connectedClients.add(senderAddress);
        }

        for (InetAddress addr : connectedClients) {
            byte[] data = receivedPacket.getData();
            DatagramPacket sendPacket= new DatagramPacket(data,  0, receivedPacket.getLength(), addr, receivedPacket.getPort());
            listenerSocket.send(sendPacket);
        }
    } catch (IOException e) {
        // ...
    }
}

Basically it should relay the message to every single client who've ever sent any data but somehow it only sends its to its original sender the rest of clients miss it. 基本上,它应该将消息转发给曾经发送过任何数据的每个客户端,但是以某种方式,它只会将消息发送给其原始发件人,而其余的客户端则会丢失它。 the code is trolling with me 代码跟我一起拖

This is the NAT traversal problem as you have figured out. 您已经知道这是NAT遍历问题。

Here's a few hints: 这里有一些提示:

  1. The server can be hardcoded to listen on port 2706. But it shouldn't make any assumptions about what source port of received packets are. 可以对服务器进行硬编码以侦听端口2706。但是,不应对接收到的数据包的源端口进行任何假设。 From your code, it doesn't look like you ever attempt to call setPort . 从您的代码看来,您似乎从未尝试调用setPort So even if the NAT wasn't mapping your port number differently, I'm not sure how your original code was even getting the any destination port set. 因此,即使NAT并没有以不同的方式映射您的端口号,我也不知道您的原始代码是如何获得任何目标端口集的。 But I think you figured this out based on your own answer and your updated code. 但是我认为您是根据自己的答案和更新的代码来解决这个问题的。

  2. Don't hardcode a client port on the client's socket. 不要在客户端套接字上对客户端端口进行硬编码。 Choose port "0" (or don't set one) on your socket to let the OS choose the first available port for you. 在套接字上选择端口“ 0”(或不要设置一个端口),以使操作系统为您选择第一个可用端口。 If you have multiple clients behind the same NAT, this behavior will allow for quicker client restarts, multiple devices behind the same NAT, and other nice things. 如果您在同一个NAT后面有多个客户端,此行为将使客户端重新启动更快,同一个NAT后面有多个设备以及其他好处。

Holly Molly! 我的妈呀! I finally figured it out , it was my own fault I wasn't considering my cellphone provider's Nat and was assuming 2706 port in public IP as well. 我终于弄清楚了,这是我自己的错,我没有考虑我的手机提供商的Nat,并且还假定了2706公共IP端口。

Turns out actually I was under my cellphone network's NAT and my port 2706 was converted to some hideous port number by the time it reached the server. 原来,实际上我在手机网络的NAT下,当端口2706到达服务器时,端口2706已转换为某些丑陋的端口号。 So I had to consider the port no of the actual packet received rather than the one set on the phone. 因此,我不得不考虑收到的实际数据包的端口号,而不是电话上设置的端口号。

In a nutshell it was like this 简而言之就是这样

cellphone (port 2706)-> NAT (port 40234) -> Server (port 40234) 手机(端口2706)-> NAT(端口40234)->服务器(端口40234)

and so I was actually trying to send back data to 2706 instead of 40234 -_-' 所以我实际上是在尝试将数据发送回2706而不是40234 -_-

Once I start to send back the packets at 40234 (or whatever came with the packet) instead of 2706 , it gracefully followed the path back to my android cellphone and everything was fine. 一旦我开始在40234(或数据包附带的任何东西)而不是2706发送数据包,它就优雅地遵循了回到我的Android手机的路径,一切都很好。

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

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