Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
3096 connectés 

  FORUM HardWare.fr
  Programmation
  Perl

  [Perl] lecture/écriture simultanées sur une socket

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[Perl] lecture/écriture simultanées sur une socket

n°1598554
sephiburp
Posté le 11-08-2007 à 12:51:16  profilanswer
 

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.enstimac.fr/DocFr/perl [...] io::socket
 
Et j'ai un client.pl dont voici le code :
 

Code :
  1. use IO::Socket;
  2. use warnings;
  3. use strict;
  4. my ($sock, $kidpid);
  5. $sock = IO::Socket::INET->new(Proto     => "tcp",
  6.                               PeerAddr  => "192.168.0.11",
  7.                               PeerPort  => 9000)
  8.                         || die "Failed : $!";
  9. $sock->autoflush(1);
  10. $kidpid = fork();
  11. die "can't fork: $!" if ! defined($kidpid);
  12. if ($kidpid) {
  13.     # PERE : Ecoute des entrées clavier et envoi à la socket
  14.     while (<STDIN> ) { print $sock $_; }
  15. } else {
  16.     # FILS : Ecoute de la socket et affichage à l'écran
  17.     while (<$sock> ) { print STDOUT $_; }
  18. }
  19. 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.enstimac.fr/DocFr/perl [...] io::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 !!

mood
Publicité
Posté le 11-08-2007 à 12:51:16  profilanswer
 

n°1598667
pmarion
Posté le 12-08-2007 à 09:19:33  profilanswer
 

Bonjour,  
Je ne suis pas sûr que l'on puisse avoir le même programme pour envoyer/recevoir, et donc utiliser un fork.
 
Pour ma part j'utilise deux programmes séparés :  
Pour recevoir :  
#!/usr/bin/perl  
use strict;
use warnings;
$|=1 ;
 
use IO::Socket;
use warnings;
use strict;
my $sock = IO::Socket::INET->new(Proto     => "tcp",
                             PeerAddr  => "127.0.0.1",
                             LocalPort  => 9000,
                             Reuse=>1,  
                             Listen=>1)
                       || die "Failed : $!";
my $sock_l = $sock->accept() ;
while (1) { my $lig = <$sock_l> ;  
            last if ( $lig eq "q\n" ) ;
            print $lig if ( $lig ) ;
            select(undef, undef, undef, 0.25) ;
          }
close $sock;
_________________________________________________________________________________
Et pour envoyer :
 #!/usr/bin/perl  
use IO::Socket;
use warnings;
use strict;
 
my $sock = IO::Socket::INET->new(Proto     => "tcp",
                             PeerAddr  => "127.0.0.1",
                             PeerPort  => 9000 )  
                       || die "Failed : $!";
 
$sock->autoflush(1);
while ( 1 ) {  
  my $lig = <STDIN> ;
  print $sock $lig ;
  last if ( $lig eq "/q\n" ) ;  
}
close $sock;
 
 
 
 

n°1598676
sephiburp
Posté le 12-08-2007 à 11:38:23  profilanswer
 

pmarion a écrit :

Je ne suis pas sûr que l'on puisse avoir le même programme pour envoyer/recevoir, et donc utiliser un fork.


Pourtant, je tire cet exemple de la doc du CPAN (Lien)
 
Faire 2 programmes est une solution mais du coup, le serveur voit çà comme 2 clients distincts. çà complique tout :(
 
Selon le CPAN, c'est possible avec le même programme et un fork (donc 2 processus) :

Citation :

Une fois que vous avez obtenu la connexion au service avec lequel vous désirez discuter, appelez fork pour cloner votre processus. Chacun de ces deux processus identiques a un travail très simple à réaliser : le parent copie tout ce qui provient de la socket sur la sortie standard, pendant que le fils copie simultanément sur la socket tout ce qui vient de l'entrée standard.


Est-ce que quelqun pourrait essayer ces 2 scripts du CPAN et me dire si çà fonctionne ?
Serveur
Client

n°1598694
pmarion
Posté le 12-08-2007 à 14:29:47  profilanswer
 

Non, je ne crois pas que le serveur voie deux clients.
 
Il faut lancer d'abord le programme de réception qui sera donc le serveur et le programme d'envoi qui sera le client qui se connecte au serveur.

n°1598698
pmarion
Posté le 12-08-2007 à 14:49:19  profilanswer
 

En ce qui concerne les exemples de CPAN je les ai testés sous LINUX et ils fonctionnent.  
 
Pour Win32 il existe peut-être un problème de fork avec des vieilles versions de perl, quelle version de perl, as-tu ?

n°1598711
pmarion
Posté le 12-08-2007 à 15:23:39  profilanswer
 

Voici un exemple complet sans fork du côté client.
 
Peux-tu essayer ces deux programmes chez moi sous Win32 ou Linux ils fonctionnent  :  
 
Version serveur :
 
#!/usr/bin/perl  
use strict;
use warnings;
$|=1 ;
 
use IO::Socket;
use Net::hostent;        
 
use warnings;
use strict;
my $sock = IO::Socket::INET->new(Proto     => "tcp",
                             LocalAddr  => "127.0.0.1",
                             LocalPort  => 9000,
                             Reuse=>1,  
                             Listen=>5)
                       || die "Failed : $!";
my $client ;  
my $hostinfo ;  
while ( $client = $sock->accept() ) {
  $client->autoflush(1) ;
  $hostinfo = gethostbyaddr($client->peeraddr);
  print "Connection" . $hostinfo->name() . "\n" ;
  while ( <$client> ) {
    my $lig = $_ ;
    print $lig if ( $lig ) ;
    if ( $lig eq "who\n" ) {
      print $client "who who who who who who\n" ;
    }
    elsif ( $lig eq "motd\n" ) {
      print $client "motd motd motd\n" ;
    }
    elsif ( $lig eq "quit\n" ) {
      print "Déconnexion\n" ;
      last ;
    }
    elsif ( $lig eq "motd\n" ) {
      print $client "motd motd motd\n" ;
    }
    else {
      print $client "Commande : who motd quit\n" ;
    }
    select(undef, undef, undef, 0.25) ;
  }
}
close $sock;
 
--------------------------------------------------------------------------------------------------------------------
 
Version client
#!/usr/bin/perl  
use IO::Socket;
use warnings;
use strict;
 
my $sock = IO::Socket::INET->new(Proto     => "tcp",
                             PeerAddr  => "127.0.0.1",
                             PeerPort  => 9000 )  
#                            PeerPort  => 9000, Listen=>1, Reuse=>1  )  
                       || die "Failed : $!";
 
$sock->autoflush(1);
while ( 1 ) {  
  my $lig = <STDIN> ;
  print $sock $lig ;
  last if ( $lig eq "quit\n" ) ;  
  my $reponse = <$sock> ;
  print $reponse ;
}
close $sock;

n°1599124
sephiburp
Posté le 13-08-2007 à 18:18:21  profilanswer
 

D'abord, merci pour ton aide :)
 

pmarion a écrit :

Pour Win32 il existe peut-être un problème de fork avec des vieilles versions de perl, quelle version de perl, as-tu ?

J'ai la dernière version en date : 5.8.8 Build 822
 
Tes 2 programmes fonctionnent bien chez moi sous Win32.
Wow! Je suis bluffé. Comment ce while(1) arrive à tourner ?? Que représente ce '1' ?
 

n°1599281
pmarion
Posté le 14-08-2007 à 09:35:50  profilanswer
 

Le while (1) est l'equivalent d'une boucle sans fin (while true en shell) dont on sort heureusement avec last .
Comme d'habitude en perl, il existe plusieurs façons de générer un bloc .
 
En fait l'utilisation de fork complique la programmation pour un client simple.
En effet si le client envoie une requête et attend une réponse, il n'y a pas de raison de se compliquer la vie.
 
Par contre si l'application est plus  complexe il es nécessaire de passer au fork puisque chaque processus aura son autonomie.  
 
D'après mes tests le fork fonctionne bien en 5.8.8 sous Win32 et pour savoir ou cela bloque, il faudrait ajouter des print  "Etape xxx" à chaque étape du serveur, client père et fils pour voir ce qui se passe.  
 
Je ne sais pas sit tu veux continuer avec fork, mais je suis à ta disposition pour t'aider
 

n°1599338
sephiburp
Posté le 14-08-2007 à 11:47:57  profilanswer
 

Effectivement, un client simple (comme ton exemple), recevra une réponse seulement après avoir envoyer une requête. Cà, je l'ai compris seulement ce matin :p
 
En effet, j'ai besoin que les 2 processus (lecture et écriture) aient leur autonomie.
 
Voici mon client avec des print à toutes les étapes :
(Pour le serveur, j'ai repris ton code)
 

Code :
  1. use strict;
  2.     use warnings;
  3.     use IO::Socket;
  4.     my ($kidpid, $sock, $ligne);
  5.     $sock = IO::Socket::INET->new(Proto     => "tcp",
  6.                                   PeerAddr  => "localhost",
  7.                                   PeerPort  => 9000)
  8.                               || die "Failed : $!";
  9.     $sock->autoflush(1);
  10.     print "DEBUT\n";
  11.     die "Can't fork: $!\n" unless defined($kidpid = fork());
  12.     # Père : Lecture de la socket
  13.     if ($kidpid) {
  14.         print "1\n";
  15.         while ($ligne = <$sock> ) {
  16.             print "2\n";
  17.             print $ligne;
  18.             print "3\n";
  19.         }
  20.         print "4\n";
  21.         kill("TERM", $kidpid); # envoie SIGTERM au fils
  22.         print "5\n";
  23.     }
  24.     # Fils : Ecriture vers la socket
  25.     else {
  26.         print "A\n";
  27.         while ($ligne = <STDIN> ) {
  28.         print "B\n";
  29.         print $sock $ligne ;
  30.         print "C\n";
  31.         }
  32.     }
  33.     print "FIN\n";


Je lance serveur et client :
 
DEBUT
1
A
2
HELLO
3

 
Les étapes 1,2,3 montrent que le père a bouclé une fois car le serveur a envoyé "HELLO". Là, le père écoute toujours la socket (ligne 19).
L'étape A montre que le fils reste en écoute sur le <STDIN> (ligne 31).
 
Ensuite, je tape "who" :
 
who
B

 
Et là, on a juste l'étape B qui montre que le fils a capté le "who" mais il reste bloqué sur l'écriture de la socket (ligne 33).
Et je n'ai plus la main.
 
 
Si le fils reste bloqué sur l'écriture de la socket, c'est parce que le père est en train de l'écouter ?
 

n°1599343
antac
..
Posté le 14-08-2007 à 11:52:56  profilanswer
 

J'avais fait un truc un peu comme ca en C (jeu d'échec) et effectivement j'ai utilisé les forks

mood
Publicité
Posté le 14-08-2007 à 11:52:56  profilanswer
 

n°1599357
pmarion
Posté le 14-08-2007 à 12:06:43  profilanswer
 

Normalement l'envoi est indépendant de la réception car les sockets utilisent dans tampons et donc
en envoi de données n'est pas perdu même si le serveur n'est pas en état de répondre.
 
Si l'in connecte deux clients séparés sur un serveur simple que ne gère qu'une connexion à la fois, le deuxième client semble bloqué mais dès que le premier se déconnecte le deuxième reçoit les données et les traite.
 
Mais je ne sais même pas si c'est ton cas .
Je ne pense donc pas  

n°1599385
sephiburp
Posté le 14-08-2007 à 13:52:48  profilanswer
 

Je suis d'accord pour le serveur simple qui ne sait gérer qu'un client à la fois. D'ailleurs c'est ce que j'utilise dans le test ci-dessus.
Pour le moment, je fais une seule connexion à la fois (un seul client) donc çà ne pose pas de problème.
 
 

pmarion a écrit :

D'après mes tests le fork fonctionne bien en 5.8.8 sous Win32

Chez moi aussi, le fork a l'air de réussir.
J'obtiens bien 2 processus différent qui arrivent à bosser (les print fonctionnent par exemple).
 

pmarion a écrit :

En ce qui concerne les exemples de CPAN je les ai testés sous LINUX et ils fonctionnent.

Et si tu les teste sur Win32, n'es-tu pas non plus bloqué, côté client, après la première saisie au clavier ?
 
Peux-être faut-il paramétrer autrement la création de la socket sur Win32 (IO::Socket::INET->new) ?

n°1599462
pmarion
Posté le 14-08-2007 à 15:28:30  profilanswer
 

Quel serveur utilises-tu ?
 Est-ce lui qui gère le HELLO qui est sur ta trace ?  
Peux-tu envoyer les instructions de ton serveur ?
 

n°1599546
sephiburp
Posté le 14-08-2007 à 18:08:44  profilanswer
 

C'est bien le serveur qui gère le HELLO affiché sur la trace.
Voici le code du serveur que j'ai utilisé pour le test :

Code :
  1. use strict;
  2. use warnings;
  3. $|=1 ;
  4. use IO::Socket;
  5. use Net::hostent;
  6. my $sock = IO::Socket::INET->new(Proto      => "tcp",
  7.                                  LocalAddr  => "127.0.0.1",
  8.                                  LocalPort  => 9000,
  9.                                  Reuse      => 1,
  10.                                  Listen     => 5)
  11.                        || die "Failed : $!";
  12. my $client ;
  13. my $hostinfo ; 
  14. while ( $client = $sock->accept() ) {
  15.   $client->autoflush(1) ;
  16.   $hostinfo = gethostbyaddr($client->peeraddr);
  17.   print "Connexion de " . $hostinfo->name() . "\n" ;
  18.  
  19.   print $client "HELLO\n";
  20.   while ( <$client> ) {
  21.     my $lig = $_ ;
  22.     print $lig if ( $lig ) ;
  23.     if ( $lig eq "who\n" ) {
  24.       print $client "who who who who who who\n" ;
  25.     }
  26.     elsif ( $lig eq "motd\n" ) {
  27.       print $client "motd motd motd\n" ;
  28.     }
  29.     elsif ( $lig eq "quit\n" ) {
  30.       print "Déconnexion\n" ;
  31.       last ;
  32.     }
  33.     elsif ( $lig eq "motd\n" ) {
  34.       print $client "motd motd motd\n" ;
  35.     }
  36.     else {
  37.       print $client "Commande : who motd quit\n" ;
  38.     }
  39.     select(undef, undef, undef, 0.25) ;
  40.   }
  41. }
  42. close $sock;


 
Le serveur peut répondre au client sans problème.  
Et le client peut afficher la réponse du serveur tant qu'il ne bloque pas après la première saisie au clavier.

n°1600754
sephiburp
Posté le 19-08-2007 à 11:41:45  profilanswer
 

:cry:  
 
Je n'ai toujours pas trouvé de solution pour avoir un tel client.
 
Personne n'a déjà fais çà pour Windows ?
 
Anybody help ?


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  Perl

  [Perl] lecture/écriture simultanées sur une socket

 

Sujets relatifs
lecture d'un fichier xml à partir de vb 6.0[Perl] Liaison LDAP et Site Web
Lecture d'un .PLS en flash (intégré dans un site web)[HTML/CSS]écriture en gras
Lecture d'un fichier formatéproblème lecture d'un fichier texte
Faire un "cherche et remplace" dans un fichier en Perl ?[C] lecture depuis un microcontrôleur
Savoir fermer les fenêtres avec Perl/Tk 
Plus de sujets relatifs à : [Perl] lecture/écriture simultanées sur une socket


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR