Android上的UDP打洞技术;UDP服务器

6
我目前正在尝试在Android上实现UDP打洞,以用于我的UDP服务器。工作原理如下:
1.客户端(位于NAT后面;可能是3G等)向服务器(具有公共IP;端口也已知为45555)发送DatagramPacket。客户端会重复发送带有给定延迟的Datagram。
2.一旦服务器接收到Datagram,它会每500毫秒发送Datagrams(“信号”)。
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();

当客户端和服务器在同一私有网络中时,一切都正常。为了模拟公共服务器,我在我的计算机上运行服务器端代码,并在我的路由器上设置了一个端口(具有公共IP)。客户端将其数据包发送到路由器的公共IP地址。但是,在这两种情况下(我的智能手机通过我的无线局域网网络/ 3G或E连接到互联网),都没有接收到信号(服务器接收不到客户端的数据包)。
那么为什么打洞过程不起作用呢?
问候

“在我的路由器上设置端口”是什么意思?而且你所做的不是打洞。打洞是用于在不同 NAT 后面的两个客户端之间建立点对点连接。 - Tahlil
1
路由器将转发发送到其端口45555的任何UDP数据包到我的计算机。 - user2224350
1个回答

3
不同的套接字绑定到不同的私有端口,并使用您的NAT的不同公共端口进行发送和接收。您通过不同的套接字进行接收和发送。请使用接收数据的相同套接字发送数据。否则,您的发送套接字将使用路由器的不同公共端口向客户端NAT发送数据。这个数据包会被客户端的NAT丢弃,因为它来自相同的IP但未知的端口。

谢谢,那应该就是问题所在了。但是,在服务器端,我想同时接收和发送数据报。在Java中有没有一种方法可以同时使用同一个套接字(或使用相同的端口)发送和接收数据报? - user2224350
1
套接字是双向的,因此您可以同时发送和接收数据。但是,您可能希望处理一个线程突然关闭套接字的情况。 - Tahlil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接