Android 可以发送udp但不能接收

Android can send udp but not receive

我编写了一个基本的 udp 客户端服务器,其中一个 android 向服务器发送消息,然后服务器将其转发给其余客户端。

问题是,传入的 udp 消息到达服务器并且服务器将它们中继回去,但它们永远不会到达其余设备。

真正令人惊奇的是,如果我将服务器用作回显服务器(即仅中继到发件人),那么一切正常。所有客户端和服务器套接字都使用相同的端口 2706

服务器代码

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 发件人逻辑:

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

同时在其他线程上,接收者只是等待相同的 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();
    }
}

它永远不会比等待数据更进一步,因为它会阻塞直到它收到数据包

此外,我还可以在 wifi 和移动数据图标中看到它从未收到任何数据,但数据发送始终打开并且在服务器上看到收到

**编辑:-回声服务器**

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) {
        // ...
    }
}

基本上它应该将消息转发给曾经发送过任何数据的每个客户端,但不知何故它只将其发送给其原始发件人,其余客户端会错过它。代码在跟我玩

冬青茉莉!我终于弄明白了,这是我自己的错,我没有考虑我的 cellphone 提供者的 Nat,而是假设 public IP 中的 2706 端口也是如此。

原来我在我的小区phone 网络的 NAT 下,我的端口 2706 在到达服务器时被转换为一些可怕的端口号。所以我不得不考虑实际接收到的数据包的端口号,而不是 phone.

上设置的端口号

简而言之就是这样

小区phone(2706端口)-> NAT(40234端口)->服务器(40234端口)

所以我实际上是在尝试将数据发送回 2706 而不是 40234 -_-'

一旦我开始在 40234(或数据包附带的任何内容)而不是 2706 发回数据包,它就会优雅地沿着路径返回我的 android 单元格phone,一切都很好.

这就是你想出来的NAT穿越问题。

这里有一些提示:

  1. 服务器可以硬编码为在端口 2706 上侦听。但是它不应该对接收到的数据包的源端口有任何假设。从您的代码来看,您似乎从未尝试调用 setPort。因此,即使 NAT 没有以不同方式映射您的端口号,我也不确定您的原始代码是如何设置任何目标端口的。但我认为您是根据自己的答案和更新后的代码解决的。

  2. 不要在客户端套接字上硬编码客户端端口。在您的套接字上选择端口“0”(或不设置),让 OS 为您选择第一个可用端口。如果您在同一个 NAT 之后有多个客户端,此行为将允许更快的客户端重启、多个设备在同一个 NAT 之后,以及其他好处。