2012-04-28 161 views
9

在我看來,較新的Android設備在NAT後面運行,其中本地地址是內部運營商或LAN地址,公共地址是路由器或運營商分配的外部地址。Android:NAT穿越?

儘管如此,使用NetworkInterface的新手機不會像訪問IP檢測服務時那樣返回相同的地址。

因此,通過直接P2P SocketChannels連接固有失敗。

是否有針對Android平臺設計的此問題的常見解決方法?任何人都可以澄清是什麼導致這種類似NAT的安全問題?

任何鏈接到Java的NAT穿越教程例子文章或論文)也將理解爲有幫助的(因爲我不太清楚如何實現它在Java中)。

我當然也會接受任何其他解決方案!

+2

在Android設備中沒有內部NAT類似的東西。一個設備具有一個或多個網絡[接口](http://docs.oracle.com/javase/tutorial/networking/nifs/definition.html),如果您在正確的收聽,您可以從外部獲得連接(假設你有互聯網許可)。如果您無法檢查嘗試訪問的網絡路徑與設備之間的網絡路徑。 – zapl 2012-04-28 22:06:47

+0

NAT與終端設備無關。該設備剛分配了一個IP地址。無論是否可路由取決於接入點/ DHCP服務器。 – 2012-04-28 22:08:45

+0

它必須與終端設備有關。當使用移動網絡接口地址測試直接P2P連接時,它可以正常連接到較舊的Android設備(Epic 4G),但在連接到Galaxy S2時無法正常連接。 NetworkInterface.getNetWorkInterfaces方法返回的Galaxy地址與外部IP不匹配,而Epic 4G的地址不匹配。顯然,手機的網絡設置有所改變。 – bgroenks 2012-04-29 17:54:57

回答

0

我已經設法建立套接字,只需轉發您在路由器連接期間使用的套接字。它爲我工作。

UPDATE

如果如果使用的是Windows(IPCONFIG)或通過終端會話上的Linux(使用ifconfig)找出通過CMD.EXE您的IP地址。然後通過瀏覽器連接到它,應該有一個安全部分。在建立ServerSocket和Socket時,轉到端口轉發並打開您使用的端口。使用TCP作爲協議。 請注意,這僅適用於您嘗試從WLAN外部進行連接的情況。

+0

您能否詳細說明或提供示例?這似乎是一個有趣的概念。 – bgroenks 2012-04-29 17:32:30

+0

@ ghostsoldier23檢查我的更新 – 2012-04-29 21:31:11

+3

哦,只是端口轉發? NAT穿越的重點在於避免這一點。 – bgroenks 2012-04-30 04:10:56

6

幾乎每個您碰到的手機或PC都不會有靜態的公共IP地址,因此需要NAT穿越。這不是因爲設備;運營商或ISP將路由器放置在您的設備和公共互聯網之間。根據您的應用,通常可以使用NAT穿透庫,例如ice4jSTUNT

+0

ice4j和STUNT都不支持UDP嗎? – bgroenks 2012-04-29 17:38:08

4

我在我自己的項目中這樣做,發現這個問題並不複雜。

下面是一個非常簡單的UDP回顯服務器節點。JS

var dgram = require('dgram'); 

var socket = 
    dgram.createSocket('udp4'); 

socket 
    .on('listening', function() 
    { 
     var address = socket.address(); 
     console.log('socket listening ' + 
      address.address + ':' + address.port); 
    }) 
    .on('error', function(err) 
    { 
     console.log('socket error:\n' + err.stack); 
     socket.close(); 
    }) 
    .on('message', function(message, rinfo) 
    { 
     console.log('message: ' + message + ' from ' + 
      rinfo.address + ':' + rinfo.port); 

     var msg = new Buffer(rinfo.address + ':' + rinfo.port); 
     socket 
      .send(msg, 0, msg.length, 
       rinfo.port, rinfo.address, 
       function(err, bytes) 
       { 
        //socket.close(); 
       }); 

    }) 
    .bind(15000); 

一個Android客戶端只需發送一個味精到這個節點服務器

     System.out.println("UDP hole punching======================="); 

         class IOth extends Thread 
         { 
          @Override 
          public void run() 
          { 

           String sendMsg = "UDP hole punching"; 
           byte[] buf = sendMsg.getBytes(); 
           DatagramPacket packet; 

           System.out.println(HPremoteHost); // node server IP 
           System.out.println(HPremotePort); // 15000 
           try 
           { 
            packet = 
              new DatagramPacket(buf, buf.length, 
                InetAddress.getByName(HPremoteHost), HPremotePort); 

            ds.send(packet); 


           } 
           catch (Exception e) 
           { 
            System.out.println("error================"); 
            System.out.println(e); 
           } 
          } 
         } 

         IOth io00 = new IOth(); 
         io00.start(); 

Android客戶端UDP聽者通過UDPholepunching

     class IOLoop extends Thread 
         { 
          @Override 
          public void run() 
          { 
           try 
           { 
            String msg = "Native.UDPserver.open"; 

            SocketAddress sockAddress; 
            String address; 


            byte[] buf = new byte[1024]; 
            DatagramPacket packet = new DatagramPacket(buf, buf.length); 
            while (true) 
            { 
             try 
             { 
              ds.receive(packet); 
              sockAddress = packet.getSocketAddress(); 
              address = sockAddress.toString(); 

              msg = new String(buf, 0, packet.getLength()); 

              System.out.println(msg + " received !!! by " + address); 

              //this case is UDP HolePunching reaction 
              if (address.equals(HPaddress1)) 
              { 
               System.out.println(msg + "hole punched"); 

               //So you can obtain own Global ip& port here. 
               //exchange this information 
               //`remoteHost` `remotePort` to another client 
               //with some method (signaling server) 

              } 
             } 
             catch (IOException e) 
             { 
             } 
            } 

           } 
           catch (Exception e) 
           { 
           } 
          } 
         } 

         IOLoop io00 = new IOLoop(); 
         io00.start(); 

獲得普通味精和自己的全球IP &端口使用其他客戶端IP的Android客戶端UDP發件人remoteHostremotePort

     class IOth extends Thread 
         { 
          @Override 
          public void run() 
          { 

           String sendMsg = "This is a test message"; 
           byte[] buf = sendMsg.getBytes(); 
           DatagramPacket packet; 

           try 
           { 
            packet = 
              new DatagramPacket(buf, buf.length, 
                InetAddress.getByName(remoteHost), remotePort); 

            ds.send(packet); 

           } 
           catch (Exception e) 
           { 

           } 
          } 
         } 

         IOth io00 = new IOth(); 
         io00.start(); 
+0

很好的答案!假設它有效( - : – wires 2014-03-14 18:56:30

+0

你發佈的代碼的目的是什麼? – 2016-06-13 12:32:39

+0

目的是回答這個問題 – 2016-06-13 22:36:39