打孔后没有进行TCP连接

时间:2015-03-22 03:48:04

标签: java android sockets tcp hole-punching

所以我试图在两个移动设备(Android移动设备和带USB移动宽带调制解调器的笔记本电脑)之间实现TCP打孔。我使用连接到wifi的另一台笔记本电脑充当服务器。

我首先让笔记本电脑连接到服务器,该服务器显示其公共IP地址和服务器看到的NAT端口号。

 try{
        System.out.println("connect to server");

        Socket connectToServer = new Socket();
        System.out.println("49");
        connectToServer.bind(new InetSocketAddress(myIPAddress.getHostAddress(), myPort));
        System.out.println("51");
        connectToServer.connect(new InetSocketAddress(serverIPAddress.getHostAddress(), serverPort));
        System.out.println("connected to server: " + connectToServer);
        connectToServer.close();

    }
    catch (Exception e){
        System.out.println("Exception 1 :" + e.toString());
        //connectToServer.close();
    }

移动设备做同样的事情,所以我看到它的公共IP和NAT的端口号。 笔记本电脑和移动设备都关闭了与服务器的连接。

然后,笔记本电脑使用相同的本地IP和端口号(用于连接服务器)和移动设备的公共IP和NAT端口号连接到移动设备。

    try{
        Socket punchSocket = new Socket();
        System.out.println("33");
        punchSocket.bind(new InetSocketAddress(myIPAddress.getHostAddress(), myPort));
        System.out.println("35");
        punchSocket.connect(new InetSocketAddress(mobileAddress.getHostAddress(), mobilePort));
        punchSocket.close();


    }
    catch(Exception e){
        System.out.println("exception 2 caught " + e.toString());

    }

由于移动电话落后于nat,因此连接超时,我得到例外。

try{
                Socket mobileSocket = new Socket();
                System.out.println("105");
                mobileSocket.bind(new InetSocketAddress(myIPAddress.getHostAddress(), myPort));
                System.out.println("124");
                mobileSocket.connect(new InetSocketAddress(mobileAddress.getHostAddress(), mobilePort));
                System.out.println("connection made: " + mobileSocket);
                mobileSocket.close();


            }
            catch(Exception e){
                System.out.println("exception 2 caught " + e.toString());

            }

最后,我尝试再次连接到手机。当笔记本电脑试图连接到手机时,我也会通过手机发起连接。使用相同的IP和端口(用于连接服务器的移动设备),我连接到笔记本电脑的公共IP和端口。

但手机和笔记本电脑都试图连接超时。

我第二次尝试让笔记本电脑听取连接,而不仅仅是尝试从笔记本电脑连接到移动设备:

        ServerSocket welcomeSocket = new ServerSocket(myPort, 50, myIPAddress);

        welcomeSocket.setSoTimeout(5);
        System.out.println("Start listening for mobile to connect");


        while(true){
        try{
            Socket newsock = welcomeSocket.accept();
            System.out.println("connection made: " + newsock);

            }
        catch(Exception e) {
            System.out.println("exception 4 caught " + e.toString());

           }
         }

但这也没有奏效。我不知道为什么。有没有办法让我测试我的移动服务提供商的NAT是否会允许打孔?

这是我通过手机连接的方式:

try {
        Log.d("stop", "line 64");
        InetAddress serverIPAddress = InetAddress.getByName(serverIP);
        InetAddress myIPAddress = InetAddress.getByName(myIP); //InetAddress.getLocalHost(); 
        Log.d("stop", "line");
        Log.d("localHost: ", myIPAddress.getHostAddress());
        Socket clientSocket = new Socket();
        Log.d("stop", "line 70");
        clientSocket.bind(new InetSocketAddress(myIPAddress.getHostAddress(), myPort));
        Log.d("stop", "line 72");
        clientSocket.connect(new InetSocketAddress(serverIPAddress.getHostAddress(), serverPort));
        Log.d("stop", "line 74");

        BufferedReader inFromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
        receivedMessage = inFromClient.readLine();
        Log.d("stop", "line 78");


        clientSocket.close();
        //Toast.makeText(this, "socket connected", Toast.LENGTH_SHORT).show();

        return receivedMessage; //receivedMessage;
    } catch (IOException e) {

        //Toast.makeText(this, "socket caughyt", Toast.LENGTH_SHORT).show();
        e.printStackTrace();
        error1 = "no Server";
        Log.d("error", error1 + e.getMessage());
    }

我今天大部分时间都在努力解决这个问题。当在笔记本电脑上使用serversocket时,移动设备上的错误是超时。它昨晚(凌晨1点)随机工作了一次,我去睡觉了。今天不再工作了。 不知道为什么不。 任何帮助将不胜感激。

编辑:

好的,现在,在笔记本电脑尝试连接到移动设备并失败(然后不断尝试连接到移动设备而不是服务器插座方案)之后,移动设备会尝试连接到笔记本电脑并通过。如果我删除这些行:     BufferedReader inFromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));             receivedMessage = inFromClient.readLine(); 然后手机说已经连接了。如果我留下线路,移动设备会收到对端重置连接的错误。

然而,在任何一种情况下,笔记本电脑似乎都没有响应。如果我使用服务器套接字替代而不是尝试从笔记本电脑连接,则移动设备在连接超时时无法尝试连接。

1 个答案:

答案 0 :(得分:0)

看起来您有一个很好的解决方案,可以找到两个设备的正确公共地址。但是,即使有了这些信息,许多(甚至可能是大多数)移动网络仍然不允许传入TCP连接到移动设备。

有些人会对不同的设备类型有不同的限制,这可能就是为什么你看到它有时可以使用移动宽带调制解调器,但从不使用手机。这些差异甚至可能仅仅是因为调制解调器和电话连接在运营商网络中的设置不同(例如,使用具有不同规则的不同APN)。

您很可能知道,但您仍然可以使用服务器作为中间的“中继”点进行端到端通信 - 这显然会增加您的解决方案的服务器端复杂性,但它具有在大多数情况下可靠工作的优势运营商。该方法看起来像:

  • 笔记本电脑连接到服务器
  • 移动连接到服务器
  • 笔记本电脑向服务器询问已连接设备的列表并'发现'移动
  • 笔记本电脑为移动设备发送消息。它实际上将消息发送到服务器,并指示它将被发送到移动设备。
  • 服务器通知移动设备有可用的消息(例如,使用某种类型的消息通知,例如Google Cloud Messaging,或者只是定期轮询设备以查看是否有消息)。
  • 移动设备从服务器检索消息。