I'm currently trying to implement punching a UDD hole on Android for my udp server. Everything should work as follows:
- The client (for nat, maybe 3G, ..) sends the DatagramPacket to the server (the server has a public ip; the port is also known as 45555). The client retries sending the datagram with the specified delay.
- After the server receives a datagram, it sends datagrams ("signals") every 500 ms.
- If the hole punching worked, the client should receive these signals.
Here is my current client implementation (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
Here is the server implementation (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();
Everything works when the client and server are on the same private network. To emulate a public server, I run the server-side code on my computer and configure the port on my router (which has a public ip) *. Clients will forward their packets to the public IP address of the router. But in both cases (my smartphone is connected to the Internet through my wlan / 3G or E network) no signals are received (the server receives client datagrams)
So why does the hole punching process not work?
considers
*: the router forwards any udp packets sent to its port 45555 to my computer
source share