IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Programmation et administration système Perl Discussion :

Serveur Client : pas de réponse !


Sujet :

Programmation et administration système Perl

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 14
    Par défaut Serveur Client : pas de réponse !
    Je viens d'ecrire (recopier) ce script : un serveur qui attend une requete et qui l'affiche. et puis qui renvoie une réponse au client.

    j'ai essayé de me connecter au serveur avec mon navigateur internet, avec telnet et aussi avec un client en perl (je demande l'adresse 127.0.0.1).
    Le serveur m'affiche bien la requete envoyée mais ne renvoie rien au client et le navigateur cherche localhost sans y arriver.

    (notez que je fais tout en local)

    code du serveur :
    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    #!C:/Perl/bin/perl.exe
    use strict;
    use warnings;
    use Socket;
    
    
    my ($serveur,$ipServ,$paddr,$proto);
    my $port =80;
    
    
    my $texte = "hello bob";
    
    
    $serveur='localhost';
    
    $ipServ=gethostbyname($serveur);
    $proto = getprotobyname('tcp');
    
    $paddr = (sockaddr_in( $port, INADDR_ANY )or die ("impossible"));
    
    socket( SOCK, PF_INET, SOCK_STREAM, $proto ) or die "socket: $!";
    
    bind (SOCK,$paddr)|| die ("Liaison impossible.\n");
    
    listen (SOCK, 1)|| die ("Liaison impossible.\n");
    
    
    my $client=accept(CLI,SOCK);
    
    print  CLI $texte;   #<==== ICI
    while (my $line = <CLI>) {
        print $line;
    }
    
    
    
    print "Connection acceptee ";
    
    
    
    
    <stdin>;
    
    close SOCK;
    close CLI;
    exit;
    donc "print CLI $texte; " devrait renvoyer hello bob au client, mais non !
    voilà le probleme ! merci d'avance

  2. #2
    Expert confirmé
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Par défaut
    C'est sans doute parce que tu n'as pas activé l'autoflush sur le socket que tu as obtenu avec accept() et qu'il n'y a pas de "\n" (retour à la ligne) à la fin de $texte, le print est bufferisé, et tu as un deadlock avec la lecture après (ton client attend que le serveur écrive et le serveur attend que le client écrive)...

    Par ailleurs je te conseille d'utiliser IO::Socket, c'est plus facile et plus robuste en général :
    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
    28
    #! /usr/bin/env perl
    use strict; use warnings;
     
    use IO::Socket;
     
    my $server = IO::Socket::INET->new(
      Proto    => "tcp",
      LocalPort => 9000,
      Listen => SOMAXCONN,
      Reuse => 1,
    ) or die "Can't setup server\n";
     
    my $client = $server->accept();
     
    $client->autoflush(1);
    print $client "Hello bob\n";
     
    while( <$client> ) {
      print;
    }
    $client->close();
     
    print "A connection was accepted (press Enter to quit).\n";
    <STDIN>;
     
    $server->close();
     
    __END__
    --
    Jedaï

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 14
    Par défaut
    voilà c'était ça, ça marche ! merci

    le print est bufferisé, et tu as un deadlock avec la lecture
    bufferisé, deadlock, queke ça signifie ?

    en fait, j'ai un peu cherché, je comprends pas bien ce qu'est le buffer...
    je ne comprends pas non plus cette ligne qui vide le tampon (et qui revient au même que l'autoflush si j'ai bien compris) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select( ( select(SOCK), $| = 1 )[0] );
    plus précisement, je ne comprends pas : ( select(SOCK), $| = 1 )[0]

    Par ailleurs je te conseille d'utiliser IO::Socket
    en fait j'essaie de comprendre quelques fonctions de base sur les sockets, voilà pourquoi je refait tout à la main

  4. #4
    Expert confirmé
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Par défaut
    Citation Envoyé par Canopus
    bufferisé, deadlock, queke ça signifie ?
    Un buffer (aussi appelé tampon en français) est une zone mémoire où les entrées ou les sorties sont stockés temporairement, de façon à les accumuler de sorte que les "véritables" entrées/sorties soient moins nombreuses et plus volumineuses (car faire des entrées/sorties est très couteux indépendamment de leur taille, quel que soit l'OS (car on est obligé de faire un appel système et d'attendre le matériel)). Une sortie bufferisée (horrible anglicisme mais bon...) est une sortie qui va passer par un buffer, c'est le cas en Perl des sorties effectuées avec print().
    En réalité il n'est pas possible de faire en sorte que print() ne soit plus bufferisé, mais on parvient à un résultat similaire en activant l'autoflush, qui en fait effectue automatiquement un flush() après chaque print() : flush() est une fonction (non accessible directement depuis Perl) qui va vider le buffer en effectuant une véritable sortie immédiatement.
    Pour activer l'autoflush sur un handle de fichier il faut placer la variable spéciale $| à une valeur vraie (1 par exemple) lorsque le handle est actif. Par défaut à l'origine c'est STDOUT qui est actif, et pour changer de handle actif il faut utiliser select(). Par exemple pour activer l'autoflush sur FILE :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    select( FILE );
    $| = 1;
    Mais ce bout de code a un problème : il ne réactive pas le handle de fichier précédemment sélectionné après avoir activé l'autoflush. Or la plupart des programmeurs assume que STDOUT est sélectionné par défaut et écrive :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    print "Hello world ! \n";
    En assumant que l'affichage se fera sur la sortie standard, mais en réalité si le HANDLE de sortie n'est pas explicite, print() écrit sur le handle actuellement actif, autrement dit FILE après notre bout de code précédent, et non pas STDOUT...
    C'est pourquoi on utilise plutôt un code qui resélectionne le handle précedemment actif, aidé en cela par le fait que select() retourne ce handle :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    my $oldfh = select( FILE );
    $| = 1;
    select($oldfh);
    Ou de façon plus idiomatique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select( ( select(FILE), $| = 1 )[0] );
    En fait, on a :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ( select(FILE), $| = 1 )[0]
    qui active FILE, puis active l'autoflush sur FILE, les deux instructions sont entourées par des parenthèses, qui en font un pseudo-tableau, dont les valeurs sont (handle précédemment sélectionné, 1) = (valeur de retour de select(FILE), valeur de ($| = 1)), on prend la première de ces valeurs avec [0], et on la select()ionne, revenant ainsi à la situation préalable à cette ligne, mais avec l'autoflush activé sur FILE... (la valeur de ($| = 1) est 1 de façon à pouvoir écrire $x = $| = 1 et obtenir le résultat intuitif)

    Un deadlock est une situation où deux processus/threads s'exécutant concurremment (autrement dit en même temps et parallèlement) attende chacun que l'autre le débloque avant de débloquer l'autre, ils ne se débloqueront donc jamais d'eux-même et c'est une cause fréquente de bugs dans les modèles classiques de concurrence.

    --
    Jedaï

  5. #5
    Expert confirmé
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Par défaut
    Si tu utilises un Perl récent (disons 5 ans, tout est relatif ) et des filehandles lexicaux, en important IO::Handle tu bénéficieras de méthodes intéressantes sur les filehandles comme "par exemple" autoflush() :
    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
    #!/usr/bin/perl
    use strict; use warnings;
     
    # utiliser plutôt FileHandle si on n'est pas sûr de la version de Perl
    use IO::Handle;
     
    my $filename = shift;
     
    open my($file), '>', $filename
      or die "Can't open $filename : $!\n";
     
    $file->autoflush(1);
     
    for(my $i = 1;;$i++) {
      print $file "ok $i\r";
      sleep(1);
    }
     
    __END__
    --
    Jedaï

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 14
    Par défaut
    J'essaie maintenant de créer un tchat, entre le serveur et le client

    ce code serveur permet d'envoyer du texte au client
    Code Perl : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while (1) {
    	my $send=<stdin>;
    	print CLI $send; 
    }

    ce code permet d'en envoyer et d'en récuperer
    Code Perl : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    while (my $line=<SOCK>) {
                 print $line;
    	my $send=<stdin>;
    	print CLI $send; 
    }

    et le problème est que les infos envoyés par le client ne peuvent pas arriver en "direct live" mais seulement après avoir validé la valeur de $send. comment faire tourner en parallèle une boucle qui reçoit et affiche les infos, et une autre qui permette de les envoyer ?...
    je me suis un peu renseigné sur fork mais on ne l'utilise pas dans ce cas précis à ce que j'ai cru comprendre, et puis fork ne tourne pas sous windows.

    2ème petit problème :
    j'essaie cette fois d'envoyer avec mon serveur du HTML à un navigateur internet (j'ai utilisé IE6 pour le coup), donc j'ai récupéré une requète de réponse avec ethereal :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    my $texte2 = join (
    "\015\012" => 
    "HTTP/1.1 200 OK",
    "Date: Wed, 20 Jun 2007 10:40:29 GMT",
    "Server: Apache/2.2.2 (Fedora)",
    "Last-Modified: Mon, 24 Apr 2006 07:45:49 GMT",
    "ETag: \"c00ca59-cc-6d532540\"",
    "Accept-Ranges: bytes",
    "Content-Length: 204",
    "Connection: close",
    "Content-Type: text/html",
    "",
    "<html><head><title>Vous Etes Perdu ?</title></head><body><h1>Perdu sur l'Internet ?</h1><h2>Pas de panique, on va vous aider</h2><strong><pre>    * <----- vous &ecirc;tes ici</pre></strong></body></html>"
    );
    suivi de :
    et IE rame sans rien afficher quand je le connecte à 127.0.0.1
    le nom du serveur et les dates correspondent pas mais j'imagine que ça vient pas de ça...

    ps : merci pour les explications sur l'autoflush

Discussions similaires

  1. Réponses: 8
    Dernier message: 27/07/2009, 11h23
  2. Mon Alias marche sur le Serveur mais pas sur le Client
    Par Aquellito dans le forum Windows Serveur
    Réponses: 12
    Dernier message: 26/11/2008, 09h49
  3. Pas de réponse serveur IHS
    Par RicFT dans le forum Apache
    Réponses: 3
    Dernier message: 05/12/2007, 14h09
  4. Client ne reçoit pas les réponses du serveur
    Par Joccy dans le forum Programmation et administration système
    Réponses: 1
    Dernier message: 04/10/2007, 15h16
  5. Réponses: 7
    Dernier message: 25/08/2006, 14h15

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