Java Socket не может подключиться к «0.0.0.0» с NoRouteToHostException вместо ConnectionRefused - PullRequest
0 голосов
/ 11 февраля 2019

Проблема

При открытии сокета для IP: 0.0.0.0 и Port: 37845 (просто случайный закрытый порт) с классом сокета Java, подключение к сокету завершается неудачно с java.net.NoRouteToHostException на Машина 1

Exception in thread "main" java.net.NoRouteToHostException: No route to host (Host unreachable)
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:204)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:589)
    at Test.main(Test.java:26)

Я использую этот тестовый код:

import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

public class Test {

 public static void main(String[] args) throws Exception {

  Socket socket;

  // create a socket with a timeout
  SocketAddress socketAddress = new InetSocketAddress("0.0.0.0", 37845);

  // create a socket
  socket = new Socket();

  // this method will block no more than timeout ms.
  int timeoutInMs = 10 * 1000; // 10 seconds
  socket.connect(socketAddress, timeoutInMs);
  System.err.println("SUCCESS");
 }
}

Ожидаемый

То, что я на самом деле ожидаю, это java.net.ConnectException : Connection refused (Connection refused), который такжечто я получаю с другой машиной Cent OS, назовем это Machine2 :

Exception in thread "main" java.net.ConnectException: Connection refused (Connection refused)
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:204)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
        at java.net.Socket.connect(Socket.java:589)
        at Test.main(Test.java:26)

Настройка

Machine1:

[qa@jenkins-staging ~]$ cat /etc/centos-release
CentOS Linux release 7.6.1810 (Core)
[qa@jenkins-staging ~]$ java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)
[qa@jenkins-staging ~]$ uname -a
Linux jenkins-staging.fancydomain 3.10.0-514.el7.x86_64 #1 SMP Tue Nov 22 16:42:41 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

Machine2:

[qa@localhost ~]$ cat /etc/centos-release
CentOS Linux release 7.6.1810 (Core)
[qa@localhost ~]$ java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)
[qa@localhost ~]$ uname -a
Linux localhost.localdomain 3.10.0-957.1.3.el7.x86_64 #1 SMP Thu Nov 29 14:49:43 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

Так что, похоже, единственное отличие - версия ядра.

Дополнительные вещи, которые я пробовал:

  • Я попробовал "тот же" код с python, там я всегда получаю ConnectionRefused (на Machine1 + Machine2 )

    import socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("0.0.0.0", 37845))
    
  • Pinging 0.0.0.0 на Machine1 также работает и разрешается в 127.0.0.1
  • Замена 0.0.0.0 на 127.0.0.1 в исходном коде решает проблему,и ConnectionRefused (ожидается) вместо этого повышаетсяиз NoRouteToHostException
  • Отключение Firewalld, Отключение SELinux и т. д.

Вопросы

  1. Это ошибка Java?Если так, то почему он работает на Machine2 , даже если они используют один и тот же jdk и ту же версию java?
  2. Это ошибка ядра Linux?Если так, то почему он работает с Python, когда я открываю сокет до 0.0.0.0, но не с Java?Я бы предположил, что базовые системные вызовы одинаковы.

Уточнение

В приведенном выше примере я использовал порт, который закрыт, только для демонстрационных целей.То же самое применимо, если на машине есть действительный порт прослушивания, тогда он будет ConnectionRefused против SUCCESS

Ответы [ 3 ]

0 голосов
/ 11 февраля 2019

Я бы определенно установил Wireshark на обе машины и сравнил бы все сценарии.

В частности:

https://superuser.com/questions/720851/connection-refused-vs-no-route-to-host

«Отказ в соединении» означает, чтоцелевой компьютер активно отклонил соединение ... одна из следующих причин, вероятно, является причиной:

  • Ничто не прослушивает порт
  • Брандмауэр блокирует соединение с REJECT

Сообщение ICMP «нет маршрута к хосту» означает, что ARP не может найти адрес уровня 2 для хоста назначения.Обычно это означает, что хост с этим IP-адресом не подключен или не отвечает.

Конечно, возникает вопрос, почему Python ведет себя одинаково, а Java - иначе ... ната же машина.

Опять же - я бы посоветовал вам взглянуть на Wireshark.В частности, обратите внимание на 1) трехстороннее рукопожатие TCP и 2) предшествующий ему вызов ARP.


PS: как сказано выше солодом:

0.0.0.0 ... адрес просто не маршрутизируемый.

В Windows вы можете получить WSAEADDRNOTAVAIL - Удаленный адрес не является действительным адресом

В связи с этим возникает вопрос, почему вы когда-либо получаете «ConnectionRefused».

Опять же - мне определенно любопытно, что Wireshark показывает вам.

0 голосов
/ 03 марта 2019

Я ввел код, который вы предоставили, и запустил его в системе Windows 10, я получил правильное исключение

import java.net.InetSocketAddress;
import java.net.Socket;

public class Main {

    public static void main(String[] args) throws Exception {

        new Socket().connect(new InetSocketAddress("0.0.0.0", 37845), 10_0000);
    }
}

Oracle JDK 8.0.202

Exception in thread "main" java.net.ConnectException: Connection refused: connect
    at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
    at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:204)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:589)
    at Main.main(Main.java:8)

Process finished with exit code 1
0 голосов
/ 11 февраля 2019

0.0.0.0 является специальным адресом , частью специального диапазона 0.0.0.0/8, который означает «текущая сеть» или «не определено».Вы не можете подключиться к нему, поскольку он не определен как пункт назначения.

Вот почему вы получаете NoRouteToHostException - адрес просто не маршрутизируется.Вы получите похожий сбой, если попытаетесь запустить ping 0.0.0.0 или подобную команду.

ConnectionRefused происходит, когда удаленный компьютер фактически отказывается от соединения, что обычно является признаком того, что удаленный компьютер не 'не имеет сокета для прослушивания или находится за брандмауэром.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...