我编写了一个基本的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) {
// ...
}
}
基本上它应该将消息中继到每个发送过任何数据的客户端,但不知何故它只会将其发送给其原始发送者,其余的客户端会错过它。代码跟我一起拖着
答案 0 :(得分:3)
这是您已经想到的NAT遍历问题。
这里有一些提示:
可以对服务器进行硬编码以侦听端口2706.但它不应该对接收到的数据包的源端口做出任何假设。从您的代码中,您似乎没有尝试过调用setPort
。因此,即使NAT没有以不同的方式映射您的端口号,我也不确定您的原始代码是如何获得任何目标端口集的。但我认为你根据自己的答案和更新后的代码来解决这个问题。
不要对客户端套接字上的客户端端口进行硬编码。选择端口" 0" (或者不要设置一个)让你的操作系统为你选择第一个可用的端口。如果在同一NAT后面有多个客户端,则此行为将允许更快的客户端重新启动,同一NAT后面的多个设备以及其他好处。
答案 1 :(得分:2)
实际上我实际上是在我的手机网络NAT下,我的端口2706在到达服务器时被转换为一些可怕的端口号。所以我不得不考虑收到的实际数据包的端口号,而不是手机上设置的端口号。
简而言之,就像这样
手机(端口2706) - > NAT(端口40234) - >服务器(端口40234)所以我实际上是在尝试将数据发送回2706而不是40234 -_-'
一旦我开始在40234发送回数据包(或者数据包附带的任何内容)而不是2706,它会优雅地沿着路径返回到我的Android手机,一切都很好。