Cet article traite en plusieurs parties de la programmation réseau en Perl. Celle-ci ressemble de près à la programmation réseau en C, mais la structure de Perl permet de se concentrer sur les fonctions purement réseau et de s'affranchir des aspects de gestion des interruptions et de formatage des données.
Le système audio des avions est une bonne illustration de ce principe. Le système audio est le serveur. Il possède une collection de bandes originales de film et de toutes sortes d'autres musiques qu'il propose aux passagers- les clients. Le client demande l'information en connectant le casque musical et en choisissant son morceau sur une roue numérotée.
Dans cet exemple le casque actualise le concept nommé socket par les programmeurs réseau. Les clients établissent une connexion avec la sockette du serveur en branchant le cable au serveur à une adresse bien connue (la prise dans l'accoudoir du siège), avec un numéro de port, celui choisi via la roue numérotée. Ils écoutent leur musique à l'autre bout du pipe représenté par les écouteurs.
Comme dans mon exemple de système audio embarqué, un serveur bien conçu peut traiter simultanément plusieurs clients. Par contre, contrairement à cet exemple, un client peut également s'adresser à plusieurs serveurs ou s'adresser plusieurs fois au même serveur.
use Socket; $server = "www.netmarket.com"; $port = 80; $server_addr =(gethostbyname($server))[4]; $server_struct = pack("S n a4 x8", AF_INET, $port, $server_addr); $proto = (getprotobyname(`tcp'))[2]; socket(MYSOCK, PF_INET, SOCK_STREAM, $proto)|| die "Failed to initialize socket: $!\n"; connect(MYSOCK, $server_struct) || die "Failed to connect() to server: $!\n";La première ligne de cet exemple ne fait qu'invoquer le module Socket.pm de perl. Ce module définit un certain nombre de constantes utiles pour la suite du programme. Ensuite vient le nom du serveur et le numéro du port auquel le client souhaite se connecter. Notez que le port 80 correspond au port sur lequel, par défaut, le serveur web écoute. Cette partie de l'information peut être passée au programme par ligne d'arguments et ensuite passée en argument à une fonction de votre programme principal.
Pour pouvoir se connecter au serveur, le programme doit traduire le
nom humain du serveur (www.netmarket.com) en une adresse
réseau. La fonction gethostbyname()
recherche le nom du
serveur et retourne une liste d'informations : l'adresse réseau du
serveur étant la cinquième. (Nous ne nous préocuperons pas des
autres pour le moment).
La structure C est crée en appliquant la fonction pack()
à cette adresse. Elle possède trois champs : une description du
type de l'adresse réseau, le numéro du port et l'adresse du
serveur à contacter (le reste de la structure est simplement remplie
de zéros). AF_INET
est une constante définie dans le
module Socket.pm, qui représente les adresses du type de Protocol
Internet (IP) (n'oublions pas que de pauvres malheureux doivent
programmer pour d'autres réseaux comme AppleTalk, DECnet ou X.25,
tous ont leur propre constante AF_*
dans
Socket.pm
). A moins que le programmeur ne spécifie le
type de l'adresse dans l'entête de sa donnée, le système
d'exploitation n'est pas capable de la décoder et l'établissement de
la connexion à la sockette échouera.
Maintenant que nous nous sommes débarrassé de tous ce fatras de
Au bout du compte la communication est établie. Ce n'est pas le
propos de cet article que de discuter des vertus comparées de TCP et
d'UDP. Sachez simplement que TCP est toujours la bonne solution à
moins que vous n'ayez de bonnes raisons de choisir UDP. Prenez
toujours la peine d'utiliser la fonction
En tenant fermement un des côtés de la sockette (sous la forme du
file handle
Comme ce client s'est connecté au serveur Web
www.netmarket.com, souvenez vous du port 80, le programme
client peut causer avec le serveur en utilisant le protocole HTTP :
Ceci étant fait, le client demande un fichier au serveur Web en
utilisant la command
Une fois que le client a passé sa requête, le serveur envoie le
contenu du fichier dans la sockette ( ou un message d'erreur si le
fichier n'est pas trouvé ou si une autre erreur s'est produite). Le
standard HTTP stipule que le serveur coupe la communication après
qu'il a envoyé le contenu du fichier. Le client à l'autre bout de la
sockette, interprète cette rupture de communication comme une lecture
ayant atteint la fin du fichier. Dans le programme précédant, le
contenu du fichier est simplement affiché sur le standard output.
En attendant, pratiquez ces concepts en prenant exemple sur ce
programe pour écrire une application qui prend sur la ligne de
commandes le nom du serveur, le numéro du port, le nom du fichier et
qui récupère ce fichier depuis le serveur Web distant. Impressionnez
vos amis, et améliorez votre productivité, en écrivant un robot qui
surfera sur le Web à la recherche de tag HTML dans les documents que
vous téléchargerez puis qui récupèrera également ces documents
pointés. Prenez bien garde d'arrêter la recherche à un moment, faute
de quoi vous finirez par télécharger tout le Web.
Traduit de ;login: Vol. 21 No. 4, August 1996.
pack(), nous allons pouvoir nous concentrer sur
l'établissement de la sockette. Tout d'abord le client initialise son
côté de la sockette dans une structure de file handle Perl,
MYSOCK
. Le second argument de la fonction
socket()
spécifie le type de connexion réseau, c'est à
dire la façon dont la sockette va être utilisée et le protocole de
transmission. PF_INET
est une autre constante provenant
du module Socket.pm
. Elle est liée à AF_INET
et indique que cette sockette sera du type IP ( en fait, au début
d'IP, AF-INET était utilisé à la fois dans la structure C et dans la
fonction socket()
, cette pratique est
déconseillée). SOCK_STREAM
est une 3ème constante qui
indique que la communication se déroulera sur le mode d'une
communication téléphonique. Chaque correspondant peut parler en même
temps que l'autre et la communication cesse quand l'un des deux
raccroche. (SOCK_STREAM
est la méthode de communication
la plus commune, mais il existe d'autres méthode comme
SOCK_DGRAM
qui ressemble plus à une communication par
signaux, le client et le serveur s'échangent des messages mais il n'y
a pas de garantie qu'ils les reçoivent).getprotobyname()
. Les programmeurs paresseux codent cette
valeur en dur parce qu'elle est constante sur la majorité des
UNIX. Les gens comme moi les maudissent quand ils ont à porter leur
code sur des UNIX exotiques ou sur d'autres systèmes.MYSOCK
), le client invoque
connect()
pour contacter le serveur. La fonction
connect()
prend comme argument le file handle et la
structure C que nous venons d'examiner. En supposant que l'appel à
connect()
réussisse, le client a établi sa connexion avec
le serveur.
Utilisons la
MYSOCK
peut maintenant être manipulée comme n'importe
quel file handle de Perl avec en plus la possibilité de pouvoir
écrire et lire dans la même sockette. Dans ce context d'entrées
sorties réseau, il est particulièrement important que vous terminiez
vos accès par un close()
pour économiser les
ressources réseau et système.
select(MYSOCK);
$| = 1;
select(STDOUT);
print MYSOCK "GET /\n\n";
while (<MYSOCK>) {
print;
}
close(MYSOCK);
Les 3 premières lignes arrêtent la bufferisation standard des entrées
sorties. Habituellement, il est intéressant de lire et d'écrire dans
un fichier par gros paquets (en lisant plus de données que nécessaire
ou en regroupant en une seule de nombreuses petites lectures) et la
plus part des systèmes UNIX pratiquent cette optimisation par
défaut. Cependant cette option peut être désactivée, par exemple dans
le cas d'un dialogue client serveur ou les deux parties échangent des
petits messages. Le mécanisme de bufferisation et règlé en Perl par
la variable $|
. Il suffit de la passer à une valeur non
nulle (zéro est sa valeur par défaut). L'affectation de cette variable
influe sur le file handle du dernier select()
effectué (STDOUT
est utilisé par défaut). Il faut donc
d'abord sélectionner MYSOCK
, affecter $|
,
puis selectionner à nouveau STDOUT
.GET
du protocole http. L'argument de
la commande GET
est le nom du fichier réclamé. Dans ce
cas le client demande simplement le fichier racine de l'arbre des
documents, mais il aurait tout aussi bien pu demander :
/some/other/file.html.
La requête GET
est suivie par 2 lignes vides.
Pratiquons la
L'exemple que nous venons de voir couvre les bases de l'écriture d'un
programme client. Il y a bien d'autres choses à savoir sur ce sujet,
mais il y a également beaucoup de personnes fort bien payées qui
n'en savent pas d'avantage. Dans mon prochain article j'aborderai
l'écriture d'un serveur et nous verrons un serveur Web simplifié.
Dernière édition: 23 décembre 1997 phb
Original 11/22/96pc
Back to the original
Retour à l'index