我写了一个基本的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) {
// ...
}
}
基本上它应该将消息中继到每个发送过任何数据的客户端,但不知何故它只会将其发送给其原始发送者,其余的客户端会错过它 . 代码跟我一起玩
2 回答
这是您已经想到的NAT遍历问题 .
这里有一些提示:
可以对服务器进行硬编码以侦听端口2706.但它不应该像你曾经尝试调用
setPort
一样 . 因此,即使NAT不是't mapping your port number differently, I' m,也不确定原始代码是如何获得任何目标端口集的 . 但我认为你根据自己的答案和更新后的代码来解决这个问题 .不要对客户端套接字上的客户端端口进行硬编码 . 在套接字上选择端口“0”(或不设置一个),让操作系统为您选择第一个可用端口 . 如果在同一NAT后面有多个客户端,则此行为将允许更快的客户端重新启动,同一NAT后面的多个设备以及其他好东西 .
我的妈呀!我终于明白了,这是我自己的错,我没有考虑我的手机提供商的Nat,并且在公共IP中假设2706端口 .
结果实际上我在我的手机网络的NAT下,我的端口2706在到达服务器时被转换为一些可怕的端口号 . 所以我不得不考虑收到的实际数据包的端口号而不是手机上设置的端口号 .
简而言之就是这样
手机(端口2706) - > NAT(端口40234) - >服务器(端口40234)
所以我实际上试图将数据发送回2706而不是40234 -_-'
一旦我开始在40234(或随包带来的任何东西)而不是2706发回包,它优雅地沿着路径回到我的Android手机,一切都很好 .