java - Android上的UDP打洞; UDP 服务器

标签 java android network-programming udp hole-punching

我目前正尝试在 Android 上为我的 udp 服务器实现 udp 打洞。事情应该是这样的:

  1. 客户端(在 nat 后面;可能是 3G,..)向服务器发送一个 DatagramPacket(服务器有一个公共(public) ip;端口也被称为 45555)。客户端以给定的延迟重复发送数据报
  2. 一旦服务器收到数据报,它就会每 500 毫秒发回一次数据报(“信号”)。
  3. 如果打洞成功,客户端应该收到这些信号

这是我当前的客户端实现(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/

相关文章:

java - 使用jsch进行远程端口转发?

java - IntelliJ 2018.1.3 显示接口(interface)中的所有方法,为什么?

Android - 支持 0 台设备

python - 使用 Python 搜索具有 MAC 地址的主机

cryptography - 进行 tcp 重组时计算 tcp 连接表哈希的最佳方法

java - ANDROID 两指滑动即可启动应用程序

java - 如何控制 ParallelSuite 线程数?

android - 如何拒绝 onSharedPreferenceChanged() 监听器中的更改

Android EditText软键盘问题

java - getPeerCertificates() 可以无限期或长时间阻塞吗?