[PERL] lecture/écriture sur une socket

Bonjour,

J'aimerais faire du client-serveur intéractif en Perl.

J'ai un serveur.pl qui fonctionne correctement, j'ai repris ce script : http://perl.mines-albi.fr/DocFr/perlipc.html#serveurs%20tcp%20avec%20io::socket

Et j'ai un client.pl dont voici le code :

use IO::Socket;
use warnings;
use strict;

my ($sock, $kidpid);

$sock = IO::Socket::INET->new(Proto     => "tcp",
                              PeerAddr  => "192.168.0.11",
                              PeerPort  => 9000)
                        || die "Failed : $!";
$sock->autoflush(1);

$kidpid = fork();
die "can't fork: $!" if ! defined($kidpid);

if ($kidpid) {
    # PERE : Ecoute des entrées clavier et envoi à la socket
    while (<STDIN>) { print $sock $_; }
} else {
    # FILS : Ecoute de la socket et affichage à l'écran
    while (<$sock>) { print STDOUT $_; }
}

close $sock;


Mon problème :
La connexion réussie, et le client reçoit et affiche les messages d'accueil du serveur.
Mais après la première ligne rentrée au clavier, çà se "bloque". Et le serveur ne recoit même pas cette ligne.

Après un déboggage "approfondi", j'en ai conclu que le processus père n'arrive pas à écrire sur la socket tant que le fils boucle sur cette même socket pour écouter.
En effet, si je ne fais que écrire ou que écouter, cà fonctionne très bien.

J'ai essayer plusieurs scripts client trouvés sur le net et j'en arrive toujours au même problème.
Même celui proposé ici réagit pareil : http://perl.mines-albi.fr/DocFr/perlipc.html#client%20interactif%20avec%20io::socket

Je suis sous Windows 2000 et j'utilise Perl 5.8.8
Est-ce à cause de Windows qui gère mal le fork() ou les sockets ?

Merci d'avance pour votre aide !!
Configuration: Windows 2000
Firefox 2.0.0.6

8 réponses

  1. Modérateur
    Salut,

    voici un exemple, à toi d'adapter
    server
    #!/usr/bin/perl
    use strict;use warnings;
    use IO::Socket;
    
    my $serveur = IO::Socket::INET->new(LocalPort => 10000,
                                        Type      => SOCK_STREAM,
                                        Reuse     => 1,
                                        Listen    => 10)
    or die "Impossible serveur tcp sur le port 10000 : $@\n";
    
    while (my $client = $serveur->accept()) {
      next if my $pid = fork;
      close($serveur);
      print "*** Debut de connexion ***\n";
      print $client "Bienvenu sur le SERVER !\n--- Je suis PID $$ ---\n";
      while( my $rep = <$client>) {
        print $rep;
        if ( $rep =~ /^QUIT/i) {
          close($client);
        }
        print "*** Fin de connexion sur PID $$ ***\n";
        exit;
      }continu {
        close($client);
      }
    }
    $SIG{CHLD} = 'IGNORE';
    __END__
    
    le client
    #!/usr/bin/perl
    use strict;use warnings;
    use IO::Socket;
    
    my $socket = IO::Socket::INET->new(Proto    => "tcp",
                                       PeerAddr => "10.0.0.5",
                                       PeerPort => 10000)
    or die "Failed : $@\n";
    
    print "*** Debut de connexion ***\n";
    while(my $reponse=<$socket>){
      print "Le serveur a dit : $reponse";
      print $socket "Au revoir SERVEUR!!!\n";
    }
    print "*** Fin de connexion ***\n";
    __END__
    
    Sur le serveur
    lami20j@deb:~$ perl ccm.pl
    *** Debut de connexion ***
    Au revoir SERVEUR!!!
    *** Fin de connexion sur PID 12855 ***
    
    Sur le client
    lami20j@debian:~$ perl ccm.pl
    *** Debut de connexion ***
    Le serveur a dit : Bienvenu sur le SERVER !
    Le serveur a dit : --- Je suis PID 12855 ---
    *** Fin de connexion ***
    lami20j@debian:~$
    

    7
    1. re bonjour,

      bien voila, apres quelques tests, j'ai reussi a faire fonctionner le premier code que tu as posté sur XP, il m'as fallu placer cette commande " waitpid($pid,0); ", juse avant la boucle while du pid pere ..

      voila dis moi si pour toi, cela resous le soucis
      0
      1. Bonjour,
        Quand tu dis: "j'ai reussi a faire fonctionner le premier code que tu as posté sur XP" tu parle du premier code posté par Sephibur ou Lami20j?
        0
    2. bien j'avou que j'ai exactement le meme soucis que toi, peu importe les codes testés, je ne peux que lire dans la socket, ou que ecrire dessus, mais pas les deux, et ce soucis ne se pose que sous windows ..

      sous linux, aucun soucis, donc j'en deduis comme toi, un soucis de fork() avec windows..

      Pour ce qui concerne les threads, je ne vois pas trop comment organiser mon code pour faire le serveur.

      Si il y aurait kk1 pour eclairer cette situation .. Merci :)
      0
      1. Effectivement, tes sources sont fiables, même si je trouve que ça ne sonne pas très bien.

        Dans mon message précédent, je proposais l'utilisation des threads.

        Débutant dans ce langage, je viens de découvrir à quel point le modèle de thread est mauvais en PERL.

        Les variables ne sont pas partagées par défaut entre les threads. Il faut préciser le mot clé shared pour les rendre partagées. Bon, pourquoi pas.

        Toutefois, les types structurés ou objets sont partageables que si les éléments qui le composent sont partageables. Ainsi, il devient impossible de partager un socket. Ainsi, la solution d'avoir un thread qui consomme et l'autre qui écrit n'est plus viable.

        Quelqu'un saurait-il comment outrepasser cette limitation du modèle de thread de PERL ?
        0
      2. Petite remarque hors sujet.

        Le mot socket est masculin.

        Sinon, on écrit aussi une soquette, mais c'est autre chose.

        Sinon, pour compléter un peu le sujet, il t'est possible de faire un thread plutôt que de créer un processus avec un fork pour lire et écrire simultanément sur ton socket.
        0
        1. Modérateur
          Toujours hors sujet

          Semble-t-il que certains traducteurs spécialisés pense que socket c'est un féminin, vu qu'il s'agit d'une association d'une adresse IP et d'un numéro de port

          Exemple :

          Livre TCP/IP 3ème édition, Edition O'Reilly - Traduction Emmanuel Chaput et Stéphane Larroque

          Je cite depuis Page 50
          L'association d'une adresse IP et d'un numéro de port est appelée une socket

          Livre Perl en Action, Edition O'Reilly - Traduction Sébastien Blondeel

          Je cite depuis Page 702

          La fonction socket crée une socket, la fonction bind donne à une socket un nom local, la fonction connect connecte la socket à une autre socket, qui peut être distante, la fonction listen prépare une socket à recevoir des connexions d'autres socket ......

          On peut communiquer via une socket ...


          Livre Programmation en Perl, 3ème edition, Editon O'Reilly - Traduction Philippe Bruhat, Kai Carver et Gérald Sédrati

          Je cite
          Glosaire Page 974

          socket - ..... La chose la plus importante concernant une socket est son adresse réseau.....

          Page 409
          Bien que les sockets aient été inventées sur BSD, elles se sont rapidement répandues....

          Page 746

          Cette fonction ouvre une socket du type spécifié...


          Livre Programmation système en C sous Linux par Christophe Blaess

          Je cite
          Page 132

          Ces données peuvent être transmises sur une socket TCP/IP avec une priorité ....

          Page 516

          Les programmes offrant des services réseau peuvent choisir d'utiliser leur propre système de connexion, construisant une socket et restant à l'écoute ....

          0
      3. Modérateur
        Re,

        Mais le client que tu proposes ne fait que lire la socket.
        Il écrit aussi Au revoir SERVEUR !!!

        J'aimerais avoir un client qui écrit et lit simultanément sur une socket, d'où l'utilisation d'un fork avec un père qui écrit et un fils qui lit.
        Rappel du problème : le père bloque sur l'écriture de la socket tant que le fils boucle pour la lire.


        Ok, je vais voir ça ;-)
        0
        1. bonsoir lami, merci pour ta réponse.
          Mais le client que tu proposes ne fait que lire la socket.

          J'aimerais avoir un client qui écrit et lit simultanément sur une socket, d'où l'utilisation d'un fork avec un père qui écrit et un fils qui lit.
          Rappel du problème : le père bloque sur l'écriture de la socket tant que le fils boucle pour la lire.

          J'essaierai tout de même les paramètres de ton exemple que je n'ai jamais utilisé (Type=>SOCK_STREAM pour la création de l'objet et $SIG{CHLD}='IGNORE' ...)
          0
          1. Je relance ma question,
            Une idée chez quelqu'un ?
            0