1. #1
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    décembre 2006
    Messages
    1 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : décembre 2006
    Messages : 1 644
    Points : 2 034
    Points
    2 034

    Par défaut ServerSocket, Debian et IPv6 only.

    hello,

    j'ai bien dû galérer une heure sur une broutille à propos d'un serveur TCP codé en Java.

    Le problème: j'ai voulu réutiliser un code autour d'un ServerSocket (pour l'écoute sur un port TCP, donc) qui marchait parfaitement depuis des lustres.

    Le code ressemblant à ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    // ...
    ServerSocket listener = new ServerSocket(monPortAEcouter);
    Socket client = listener.accept();
    // ...
    Le code du 'nouveau' serveur fonctionnait parfaitement sous Windows Seven, et les clients pouvaient se connecter sans souci. Mais dès que je testais le même code sur sous Debian, rien à faire: impossible aux clients d'établir une connexion en 127.0.0.1: la connexion était systématiquement refusée.

    J'ai finalement trouvé l'origine du problème et la solution: la socket serveur n'écoutait en fait que sur l'interface IPv6 (et pas IPv4) et donc un 'telnet 127.0.0.1 monPort' était réfusé alors qu'un 'telnet ::1 monPort' marchait parfaitement. La raison: sur les distributions Debian squeeze et postérieures, un paramètre 'bindv6only' est activé par défaut (ie. mis à 1). Editer le fichier '/etc/sysctl.d/bindv6only.conf' et y mettre la valeur '0' résout le souci.



    Voilà pour la (trop) longue introduction.
    Mais cela m'amène à deux questions:

    - je pensais naïvement que Serversocket(int port) écoutait par défaut sur toutes les interfaces réseaux et tous les protocoles (IPv4 et IPv6), ce qui n'est visiblement pas le cas. Mais dans ce cas, comment fait Java pour choisir arbitrairement un protocole et/ou une interface plus qu'une autre ?

    - y a-t-il un moyen simple pour faire une ServerSocket qui écoute sur toutes les interfaces d'une version d'IP donnée, sans passer par une itération 'manuelle' sur chaque interface comme le propose la FAQ ?

    Merci d'avance
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  2. #2
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    avril 2002
    Messages
    13 794
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : avril 2002
    Messages : 13 794
    Points : 22 676
    Points
    22 676
    Billets dans le blog
    1

    Par défaut

    Salut,



    Je pense qu'il faut préciser l'adresse IP lors de la création du ServerSocket, avec le constructeur ServerSocket(int, int, InetAddress).

    Si tu lui passes une adresse IPv4 cela devrait être OK.

    Le soucis c'est que InetAddress.getLocalHost() doit surement te renvoyer une adresse IPv6 pour que tu ai ce comportement.

    Je pense qu'il faudrait donc parcourir les NetwordInterface pour rechercher les IPv4 de ta machine...


    a++

  3. #3
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    décembre 2006
    Messages
    1 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : décembre 2006
    Messages : 1 644
    Points : 2 034
    Points
    2 034

    Par défaut

    Salut, et merci pour ta réponse.

    Le souci avec l'itération sur les NetworkInterfaces c'est que j'imagine que je vais me retrouver avec une INetAddress qui correspond à une interface spécifique (par exemple, eth0, eth1 ou lo). Donc si je veux écouter sur l'ensemble de mes interfaces réseau, je vais devoir faire autant de ServerSocket qu'il y a d'interfaces.

    J'aurais préféré (dans la mesure du possible) une solution équivalente à celle d'origine, à savoir un unique ServerSocket pour l'ensemble des interfaces en IPv4 de la machine.

    J'ai d'ailleurs noté dans la javadoc de INetAddress qu'il existait un type d'INetAddress 'wildcard' (également appelé 'anylocal' ou 'unspecified address').
    Cela semblerait correspondre à mon besoin (notamment la classe dérivée INet4Address, pour les adresses IPv4 qui semble accepter les addresses 'wildcard').
    Problème: je n'ai aucune idée de la façon dont je pourrais instancier une telle INet4Address 'wildcard' pour la passer à mon constructeur de ServerSocket.

    Si vous avez des idées ...
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  4. #4
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    avril 2002
    Messages
    13 794
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : avril 2002
    Messages : 13 794
    Points : 22 676
    Points
    22 676
    Billets dans le blog
    1

    Par défaut

    D'après cette page : http://tldp.org/HOWTO/Linux+IPv6-HOWTO/x476.html
    Il semble que cette notion d'unspecified address n'est pas spécifique à Java mais bel et bien à la couche réseau.

    Apparemment en IPv4 on utilise pour cela l'IP 0.0.0.0, donc il te faudrait faire quelque chose comme cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    new ServerSocket(monPortAEcouter, 50, InetAddress.getByName("0.0.0.0"));
    En tout cas avec 0.0.0.0 la méthode isAnyLocalAddress() retourne bien true

    a++

  5. #5
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    décembre 2006
    Messages
    1 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : décembre 2006
    Messages : 1 644
    Points : 2 034
    Points
    2 034

    Par défaut

    Citation Envoyé par adiGuba Voir le message
    D'après cette page : http://tldp.org/HOWTO/Linux+IPv6-HOWTO/x476.html
    Il semble que cette notion d'unspecified address n'est pas spécifique à Java mais bel et bien à la couche réseau.
    Effectivement, c'est une notion 'réseau', et pas spécifique à Java.
    D'ailleurs, un simple 'lsof' permet de s'en convaincre et de lister des processus qui écoutent sur un binding de type '*:monPort'.

    Apparemment en IPv4 on utilise pour cela l'IP 0.0.0.0, donc il te faudrait faire quelque chose comme cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    new ServerSocket(monPortAEcouter, 50, InetAddress.getByName("0.0.0.0"));
    En tout cas avec 0.0.0.0 la méthode isAnyLocalAddress() retourne bien true
    Excellente idée que je me suis empressé de tester.
    Malheureusement, je me retrouve avec le même comportement: uniquement les adresses IPv6 sont écoutées quand 'bindv6only' est à 1.
    Pourtant, j'ai bien le reste de mes démons (MySQL, Apache, ...) qui savent écouter sur toutes les interfaces à la fois, même avec cette option activée.
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  6. #6
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    avril 2002
    Messages
    13 794
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : avril 2002
    Messages : 13 794
    Points : 22 676
    Points
    22 676
    Billets dans le blog
    1

    Par défaut

    Peux-tu m'indiquer ce que te retourne le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    	InetAddress address = InetAddress.getByName("0.0.0.0");
    	System.out.println(address.getClass());
     
    	address = InetAddress.getByAddress(new byte[4]);
    	System.out.println(address.getClass());

    Peux-tu également tester le même code en lançant ton programme avec l'option -Djava.net.preferIPv4Stack=true

    a++

  7. #7
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    décembre 2006
    Messages
    1 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : décembre 2006
    Messages : 1 644
    Points : 2 034
    Points
    2 034

    Par défaut

    Hello,

    étonnamment, dans tous les cas, le programme affiche "class java.net.Inet4Address".

    Donc ça voudrait signifier que c'est au moment du bind que la ServerSocket ignore purement et simplement le fait que l'INetAddress qu'on lui fournit est en IPv4 et écoute quand même sur l'adresse IPv6 ?!
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  8. #8
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    décembre 2006
    Messages
    1 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : décembre 2006
    Messages : 1 644
    Points : 2 034
    Points
    2 034

    Par défaut

    Pour plus d'infos, voilà le bout de (crappy) code complet pour le test:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    package testinet;
     
    public class Main {
        public static void main(String[] args) {
            InetAddress address;
            try {
                address = InetAddress.getByName("0.0.0.0");
                System.out.println(address.getClass());
     
                address = InetAddress.getByAddress(new byte[4]);
                System.out.println(address.getClass());
     
                System.out.println("about to create a listening socket.");
                ServerSocket ss = new ServerSocket(1234, 50, InetAddress.getByName("0.0.0.0"));
                System.out.println("socket created. Waiting for a connexion.");
                Socket s = ss.accept();
                System.out.println("connexion established. Finishing program.");
     
                s.close();
                ss.close();
            } catch (Exception ex) {
                System.out.println("EXCEPTION: "+ex);
                ex.printStackTrace();
            }
        }
    }
    Avec un telnet sur la même machine:
    nouknouk@NoukServer:~$ telnet 127.0.0.1 1234
    Trying 127.0.0.1...
    telnet: Unable to connect to remote host: Connection refused

    nouknouk@NoukServer:~$ telnet ::1 1234
    Trying ::1...
    Connected to ::1.
    Escape character is '^]'.
    Connection closed by foreign host.
    La sortie du programme:

    NoukServer:/mnt/files# java -cp TestInet.jar testinet.Main -Djava.net.preferIPv4Stack=true
    class java.net.Inet4Address
    class java.net.Inet4Address
    about to create a listening socket.
    socket created. Waiting for a connexion.
    connexion established. Finishing program.
    Et on a le même comportement que preferIPv4Stack soit à true ou à false (EDIT: faux, cf. post ci-après).
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  9. #9
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    avril 2002
    Messages
    13 794
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : avril 2002
    Messages : 13 794
    Points : 22 676
    Points
    22 676
    Billets dans le blog
    1

    Par défaut

    Citation Envoyé par nouknouk Voir le message
    Donc ça voudrait signifier que c'est au moment du bind que la ServerSocket ignore purement et simplement le fait que l'INetAddress qu'on lui fournit est en IPv4 et écoute quand même sur l'adresse IPv6 ?!
    D'après ce document cela semble bien être le cas : Networking IPv6 User Guide for JDK/JRE 5.0

    En fait la JVM utilisera la couche IPv6 si elle est présente, et convertira automatiquement toutes les adresses IPv4 en IPv6. En clair lorsque tu utilises une adresse IPv4 w.x.y.z sur une machine équipé en IPv6, la JVM utilisera en réalité la couche IPv6 avec l'adresse de compatibilité :ffff:w.x.y.z

    Donc sur une machine IPv6 la JVM utilisera seulement de l'IPv6, à moins que l'on utilise l'option -Djava.net.preferIPv4Stack=true mais dans ce cas on n'utilisera QUE la couche IPv4.


    Apparemment en Java il semblerait que l'on ne puisse pas utiliser les deux couches en même temps. Soit on utilise uniquement de l'IPV4, soit de l'IPv6 avec une compatibilité IPv4.
    Or c'est justement ce que l'option "bindv6only" interdit d'où les problèmes en Java (entre autre) où toutes les adresses IPv4 deviennent alors inaccessibles.


    J'ai jeté un coup d'oeil aux bugs-report et ils se renvoient un peu la balle

    Pour le moment, je pense que la solution la plus simple est de modifier la configuration du système...

    a++

  10. #10
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    décembre 2006
    Messages
    1 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : décembre 2006
    Messages : 1 644
    Points : 2 034
    Points
    2 034

    Par défaut

    Citation Envoyé par adiGuba Voir le message
    Or c'est justement ce que l'option "bindv6only" interdit d'où les problèmes en Java (entre autre) où toutes les adresses IPv4 deviennent alors inaccessibles.

    Pour le moment, je pense que la solution la plus simple est de modifier la configuration du système...
    Effectivement, tu as tout juste.

    A noter que mon assertion précédente s'avère fausse une fois les tests refaits:
    Citation Envoyé par nouknouk Voir le message
    Et on a le même comportement que preferIPv4Stack soit à true ou à false.
    J'arrive maintenant à utiliser IPv4 avec un binding en 0.0.0.0. Je ne sais pas ce que j'ai merdouillé pour ne pas en arriver au même résultat la fois précédente

    Une dernière chose: cette solution ne me convenait pas en l'état car je ne voulais pas avoir:

    - ni une appli qui nécessite soit une configuration du système particulière (donc obliger à changer bindv6only)

    - ni même une appli qu'on devait lancer avec une option dans la ligne de commande (donc pas de "-Djava.net.preferIPv4Stack=true" non plus.

    La solution est de définir ce paramètre non pas dans la ligne de commande, mais dans le code du programme lui-même, et le tour est joué:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
                Properties props=System.getProperties();
                props.setProperty("java.net.preferIPv4Stack", "true");
    Merci pour ton éclairage fort utile
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  11. #11
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    avril 2002
    Messages
    13 794
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : avril 2002
    Messages : 13 794
    Points : 22 676
    Points
    22 676
    Billets dans le blog
    1

    Par défaut

    Attention car avec java.net.preferIPv4Stack tu ne pourras pas accéder à la couche IPv6...

    a++

  12. #12
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    décembre 2006
    Messages
    1 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : décembre 2006
    Messages : 1 644
    Points : 2 034
    Points
    2 034

    Par défaut

    Citation Envoyé par adiGuba Voir le message
    Attention car avec java.net.preferIPv4Stack tu ne pourras pas accéder à la couche IPv6...

    a++
    Effectivement, mais dans mon cas précis, cela ne me dérange pas: je préfère le non support d'IPv6 à la configuration spécifique du système.
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Création ServerSocket sur adresse local en IPV4 only
    Par papal02 dans le forum Android
    Réponses: 2
    Dernier message: 01/02/2012, 22h55
  2. [postgresql] phppgadmin + debian
    Par ohan dans le forum PostgreSQL
    Réponses: 10
    Dernier message: 31/10/2003, 11h13
  3. debian (knoppix 3.2) postgresql php phppgadmin
    Par dmalik dans le forum PostgreSQL
    Réponses: 4
    Dernier message: 26/06/2003, 08h58
  4. [controle] propriété read only
    Par Fizgig dans le forum Composants VCL
    Réponses: 6
    Dernier message: 28/08/2002, 10h30
  5. CheckBox en Read Only
    Par MrJéjé dans le forum C++Builder
    Réponses: 7
    Dernier message: 23/06/2002, 15h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo