我目前正尝试在 Android 上为我的 udp 服务器实现 udp 打洞。事情应该是这样的:
- 客户端(在 nat 后面;可能是 3G,..)向服务器发送一个 DatagramPacket(服务器有一个公共(public) ip;端口也被称为 45555)。客户端以给定的延迟重复发送数据报
- 一旦服务器收到数据报,它就会每 500 毫秒发回一次数据报(“信号”)。
- 如果打洞成功,客户端应该收到这些信号
这是我当前的客户端实现(Android):
//in onCreate()
DatagramSocket socket = new DatagramSocket(46222);
socket.setSoTimeout(2000);
final Thread t = new Thread(new Runnable(){
@Override
public void run() {
int delay = Integer.parseInt(e2.getText().toString());//e1 and e2 are EditTexts
String ip = e1.getText().toString();
try {
DatagramPacket packet = new DatagramPacket(new byte[1],1, InetAddress.getByName(ip), 45555);
while(!cleanUp){//cleanUp is set to true in onPause()
lock.lock(); //Lock lock = new ReentrantLock();
socket.send(packet);
lock.unlock();
Thread.sleep(delay);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(socket!=null)
socket.close();
}
}
});
final Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
try {
Thread.sleep(1000);
DatagramPacket packet = new DatagramPacket(new byte[1],1);
while(!cleanUp){
lock.lock();
try{
socket.receive(packet);
}catch(SocketTimeoutException e){
lock.unlock();
Thread.sleep(15);
continue;
}
lock.unlock();
final String s = tv.getText().toString()+"signal\n";
MainActivity.this.runOnUiThread(new Runnable(){
@Override
public void run() {
tv.setText(s);//tv is a TextView
}
});
Thread.sleep(10);
}
} catch (Exception e) {
e.printStackTrace();
}
finally{
if(socket!=null)
socket.close();
}
}
});
//start both threads
这是服务器端实现(Java):
//int static void main(String[] args):
final Thread t = new Thread(new Runnable(){
@Override
public void run() {
try {
DatagramPacket packet = new DatagramPacket(new byte[1],1, addr, port);
DatagramSocket socket = new DatagramSocket();
System.out.println("send");
while(true){
socket.send(packet);
Thread.sleep(500);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
final Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
try {
DatagramPacket packet = new DatagramPacket(new byte[1],1);
DatagramSocket socket = new DatagramSocket(45555);
socket.receive(packet);
addr = packet.getAddress(); //private static field InetAddress addr
port = packet.getPort();
System.out.println(addr+":"+ packet.getPort()); //field int port
t.start();
while(true){
socket.receive(packet);
System.out.println("idle");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t2.start();
当客户端和服务器在同一个专用网络中时一切正常。为了模仿公共(public)服务器,我在我的计算机上运行服务器端代码,并在我的路由器(具有公共(public) ip)* 上设置一个端口。客户端会将其数据包发送到路由器的公共(public) ip。但是在这两种情况下(我的智能手机通过我的 wlan 网络/3G 或 E 连接到互联网)都没有收到信号(服务器接收客户端的数据报)
那么为什么打洞工艺不行呢?
问候
*: 路由器会将发送到其端口 45555 的任何 udp 数据包转发到我的计算机
最佳答案
不同的套接字绑定(bind)到不同的专用端口,并使用您的 NAT 的不同公共(public)端口。您正在通过不同的套接字接收和发送。使用接收数据的同一个套接字发送。否则您的发送套接字正在使用路由器的不同公共(public)端口将数据发送到您的客户端 NAT。这个数据包被您的客户端 NAT 丢弃,因为它来自相同的 IP 但端口未知。
关于java - Android上的UDP打洞; UDP 服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32397756/