简体   繁体   English

Android上的UDP打孔; UDP服务器

[英]UDP Hole Punching on Android; UDP Server

I'm currently trying to implement udp hole punching on Android for my udp server. 我正在尝试在Android上为我的udp服务器实现udp打孔。 Things should work like this: 事情应该像这样:

  1. The client (behind a nat; maybe 3G,..) sends a DatagramPacket to the server (the server has a public ip; port is also known to be 45555). 客户端(在nat之后;可能是3G,...)向服务器发送DatagramPacket(服务器具有公共IP;端口也称为45555)。 The client repeats to send a Datagram with a given delay 客户端重复发送具有给定延迟的数据报
  2. Once the server received a Datagram, it sends Datagrams ("signals") back every 500ms. 一旦服务器收到数据报,它就会每隔500毫秒发回一次数据报(“信号”)。
  3. If hole punching worked, the client should receive those signals 如果打孔工作,客户应该接收这些信号

Here is my current Client implementation (Android): 这是我当前的客户端实现(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-side implementation (Java): 这是服务器端实现(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 client and server are in the same private network. 当客户端和服务器位于同一个专用网络中时,一切正常。 To imitate the public server I run the server-side code on my computer and set up a port on my router (which has a public ip)*. 为了模仿公共服务器,我在我的计算机上运行服务器端代码,并在我的路由器上设置一个端口(具有公共IP)*。 The clients will send its packets to the public ip of the router. 客户端将其数据包发送到路由器的公共IP。 But in both cases ( my smartphone is connected to internet via my wlan network / 3G or E) no signals are received (the server receives the datagrams of the client) 但在这两种情况下(我的智能手机通过我的wlan网络/ 3G或E连接到互联网)没有收到信号(服务器接收客户端的数据报)

So why does the hole punching process not work? 那么为什么打孔过程不起作用呢?

regards 问候

*: The router will forward any udp packets sent to its port 45555 to my computer *:路由器会将发送到其端口45555的任何udp数据包转发到我的计算机

Different sockets binds to different private port and use different public port of your NAT. 不同的套接字绑定到不同的专用端口,并使用NAT的不同公共端口。 You are receiving and sending through different sockets. 您正在通过不同的套接字接收和发送。 Send with the same socket through which you received the data. 使用您收到数据的同一套接字发送。 Else Your sending socket is using different public port of your router to send data to your clients NAT. 否则您的发送套接字使用路由器的不同公共端口将数据发送到您的客户端NAT。 This packet your clients NAT discards because it came from same IP but unknown port. 您的客户端NAT丢弃的此数据包,因为它来自相同的IP但未知端口。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM