TCP-соединение не устанавливается после перфорации

Поэтому я пытаюсь реализовать дырокол TCP между двумя мобильными устройствами (мобильный Android и ноутбук с мобильным широкополосным модемом USB). Я использую другой ноутбук, подключенный к Wi-Fi, чтобы действовать в качестве сервера.

Сначала я получаю ноутбук для подключения к серверу, который отображает его общедоступный 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());

    }

И поскольку мобильный телефон отстает от сети, время соединения истекает, и я получаю исключение.

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());
    }

Я провел большую часть сегодняшнего дня, пытаясь понять это. Когда serversock et используется на ноутбуке, ошибка на мобильном телефоне - тайм-аут. Это случайно сработало однажды прошлой ночью (1 час ночи), и я лег спать. Сегодня снова не работает. Не знаю, почему нет. Любая помощь будет оценена.

РЕДАКТИРОВАТЬ:

Хорошо, теперь, после того как ноутбук пытается подключиться к мобильному устройству и выходит из строя (а затем постоянно пытается подключиться к мобильному устройству, а не к сценарию сокета сервера), мобильное устройство пытается подключиться к ноутбуку и подключается. Если я удаляю строки: BufferedReader inFromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); receiveMessage = inFromClient.readLine(); тогда мобильный говорит, что соединился. если я оставляю линии, мобильный телефон получает ошибку, что узел сбрасывает соединение.

Однако в любом случае ноутбук, кажется, не реагирует вообще. Если я использую альтернативу сокета сервера вместо попытки подключения с ноутбука, мобильный телефон не сможет подключиться при истечении времени ожидания соединения.

1 ответ

Похоже, у вас есть хорошее решение для поиска правильных общедоступных адресов двух устройств. Однако даже с этой информацией многие (или, может быть, даже большинство) мобильных сетей по-прежнему не разрешают входящие TCP-соединения с мобильным устройством.

Некоторые из них будут иметь разные ограничения для разных типов устройств, поэтому может показаться, что они иногда работают с мобильным широкополосным модемом, но не с телефоном. Эти различия могут даже быть простыми, потому что модем и телефонные соединения устанавливаются по-разному в сетях операторов (например, используйте разные APN с разными правилами).

Скорее всего, вы в курсе, но вы все равно можете обмениваться данными сквозным образом, используя сервер в качестве "промежуточной" точки в середине - это, очевидно, увеличивает сложность серверного уровня в вашем решении, но имеет преимущество в надежности работы большинства операторов. Подход выглядит примерно так:

  • Ноутбук подключается к серверу
  • Мобильное соединение с сервером
  • Ноутбук запрашивает у сервера список подключенных устройств и "обнаруживает" Mobile
  • Ноутбук отправляет сообщение на мобильный. Фактически он отправляет сообщения на сервер с указанием, что они должны быть отправлены на мобильный телефон.
  • Сервер уведомляет мобильный телефон о том, что для него доступно сообщение (например, с помощью какого-либо уведомления о сообщениях, такого как Google Cloud Messaging, или просто с помощью устройств, которые регулярно опрашивают, чтобы узнать, есть ли у них сообщения).
  • Мобильный телефон получает сообщения с сервера.
Другие вопросы по тегам