Perl - Programmation de socket

Qu'est-ce qu'une prise?

Socket est un mécanisme Berkeley UNIX de création d'une connexion duplex virtuelle entre différents processus. Cela a ensuite été porté sur tous les systèmes d'exploitation connus permettant la communication entre les systèmes à travers l'emplacement géographique fonctionnant sur différents logiciels OS. Sans la prise, la plupart des communications réseau entre les systèmes ne se seraient jamais produites.

Regardant de plus près; un système informatique typique sur un réseau reçoit et envoie les informations souhaitées par les diverses applications qui y sont exécutées. Ces informations sont acheminées vers le système, car une adresse IP unique lui est attribuée. Sur le système, ces informations sont données aux applications concernées, qui écoutent sur différents ports. Par exemple, un navigateur Internet écoute sur le port 80 les informations reçues du serveur Web. Nous pouvons également écrire nos applications personnalisées qui peuvent écouter et envoyer / recevoir des informations sur un numéro de port spécifique.

Pour l'instant, résumons qu'une socket est une adresse IP et un port, permettant à la connexion d'envoyer et de recevoir des données sur un réseau.

Pour expliquer le concept de socket mentionné ci-dessus, nous prendrons un exemple de programmation client-serveur utilisant Perl. Pour compléter une architecture client-serveur, nous devrions suivre les étapes suivantes -

Pour créer un serveur

  • Créer une socket en utilisant socket appel.

  • Liez le socket à une adresse de port en utilisant bind appel.

  • Écoutez la prise à l'adresse du port en utilisant listen appel.

  • Accepter les connexions client avec accept appel.

Pour créer un client

  • Créer une socket avec socket appel.

  • Connectez (le socket) au serveur en utilisant connect appel.

Le diagramme suivant montre la séquence complète des appels utilisés par le client et le serveur pour communiquer entre eux -

Appels de socket côté serveur

L'appel socket ()

le socket()appel est le premier appel à établir une connexion réseau crée une socket. Cet appel a la syntaxe suivante -

socket( SOCKET, DOMAIN, TYPE, PROTOCOL );

L'appel ci-dessus crée un SOCKET et les trois autres arguments sont des entiers qui doivent avoir les valeurs suivantes pour les connexions TCP / IP.

  • DOMAINdevrait être PF_INET. C'est probable 2 sur votre ordinateur.

  • TYPE doit être SOCK_STREAM pour la connexion TCP / IP.

  • PROTOCOL devrait être (getprotobyname('tcp'))[2]. C'est le protocole particulier tel que TCP qui doit être prononcé sur la socket.

Ainsi, l'appel de fonction de socket émis par le serveur sera quelque chose comme ceci -

use Socket     # This defines PF_INET and SOCK_STREAM

socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]);

L'appel bind ()

Les sockets créées par l'appel socket () sont inutiles tant qu'elles ne sont pas liées à un nom d'hôte et à un numéro de port. Le serveur utilise les éléments suivantsbind() pour spécifier le port sur lequel ils accepteront les connexions des clients.

bind( SOCKET, ADDRESS );

Ici SOCKET est le descripteur renvoyé par l'appel socket () et ADDRESS est une adresse socket (pour TCP / IP) contenant trois éléments -

  • La famille d'adresses (pour TCP / IP, c'est AF_INET, probablement 2 sur votre système).

  • Le numéro de port (par exemple 21).

  • L'adresse Internet de l'ordinateur (par exemple 10.12.12.168).

Comme le bind () est utilisé par un serveur, qui n'a pas besoin de connaître sa propre adresse, la liste d'arguments ressemble à ceci -

use Socket        # This defines PF_INET and SOCK_STREAM

$port = 12345;    # The unique port used by the sever to listen requests
$server_ip_address = "10.12.12.168";
bind( SOCKET, pack_sockaddr_in($port, inet_aton($server_ip_address)))
   or die "Can't bind to port $port! \n";

le or die est très importante car si un serveur meurt sans connexions en suspens, le port ne sera pas immédiatement réutilisable à moins que vous n'utilisiez l'option SO_REUSEADDR en utilisant setsockopt()fonction. Icipack_sockaddr_in() La fonction est utilisée pour emballer le port et l'adresse IP au format binaire.

L'appel listen ()

S'il s'agit d'un programme serveur, il est nécessaire d'émettre un appel à listen()sur le port spécifié pour écouter, c'est-à-dire attendre les demandes entrantes. Cet appel a la syntaxe suivante -

listen( SOCKET, QUEUESIZE );

L'appel ci-dessus utilise le descripteur SOCKET renvoyé par l'appel socket () et QUEUESIZE est le nombre maximum de demandes de connexion en attente autorisées simultanément.

L'appel accept ()

S'il s'agit d'un programme serveur, il est nécessaire d'émettre un appel au access()fonction pour accepter les connexions entrantes. Cet appel a la syntaxe suivante -

accept( NEW_SOCKET, SOCKET );

L'appel d'acceptation reçoit le descripteur SOCKET retourné par la fonction socket () et une fois terminé, un nouveau descripteur de socket NEW_SOCKET est renvoyé pour toutes les communications futures entre le client et le serveur. Si l'appel d'accès () échoue, il retourne FLASE qui est défini dans le module Socket que nous avons utilisé initialement.

Généralement, accept () est utilisé dans une boucle infinie. Dès qu'une connexion arrive, le serveur crée un processus enfant pour la traiter ou la sert lui-même, puis revient à l'écoute pour d'autres connexions.

while(1) {
   accept( NEW_SOCKET, SOCKT );
   .......
}

Maintenant tous les appels liés au serveur sont terminés et voyons un appel qui sera demandé par le client.

Appels de socket côté client

L'appel connect ()

Si vous allez préparer le programme client, vous utiliserez d'abord socket() appelez pour créer une socket et vous devrez alors utiliser connect()appelez pour vous connecter au serveur. Vous avez déjà vu la syntaxe d'appel socket () et elle restera similaire à l'appel serveur socket (), mais voici la syntaxe pourconnect() appeler -

connect( SOCKET, ADDRESS );

Ici, SCOKET est le descripteur de socket renvoyé par l'appel socket () émis par le client et ADDRESS est une adresse de socket similaire à l' appel de liaison , sauf qu'elle contient l'adresse IP du serveur distant.

$port = 21;    # For example, the ftp port
$server_ip_address = "10.12.12.168";
connect( SOCKET, pack_sockaddr_in($port, inet_aton($server_ip_address)))
   or die "Can't connect to port $port! \n";

Si vous vous connectez avec succès au serveur, vous pouvez commencer à envoyer vos commandes au serveur en utilisant le descripteur SOCKET, sinon votre client sortira en donnant un message d'erreur.

Client - Exemple de serveur

Voici un code Perl pour implémenter un simple programme client-serveur utilisant le socket Perl. Ici, le serveur écoute les demandes entrantes et une fois la connexion établie, il répond simplement à Smile depuis le serveur . Le client lit ce message et l'imprime à l'écran. Voyons comment cela a été fait, en supposant que nous avons notre serveur et notre client sur la même machine.

Script pour créer un serveur

#!/usr/bin/perl -w
# Filename : server.pl

use strict;
use Socket;

# use port 7890 as default
my $port = shift || 7890;
my $proto = getprotobyname('tcp');
my $server = "localhost";  # Host IP running the server

# create a socket, make it reusable
socket(SOCKET, PF_INET, SOCK_STREAM, $proto)
   or die "Can't open socket $!\n";
setsockopt(SOCKET, SOL_SOCKET, SO_REUSEADDR, 1)
   or die "Can't set socket option to SO_REUSEADDR $!\n";

# bind to a port, then listen
bind( SOCKET, pack_sockaddr_in($port, inet_aton($server)))
   or die "Can't bind to port $port! \n";

listen(SOCKET, 5) or die "listen: $!";
print "SERVER started on port $port\n";

# accepting a connection
my $client_addr;
while ($client_addr = accept(NEW_SOCKET, SOCKET)) {
   # send them a message, close connection
   my $name = gethostbyaddr($client_addr, AF_INET );
   print NEW_SOCKET "Smile from the server";
   print "Connection recieved from $name\n";
   close NEW_SOCKET;
}

Pour exécuter le serveur en mode arrière-plan, exécutez la commande suivante à l'invite Unix -

$perl sever.pl&

Script pour créer un client

!/usr/bin/perl -w
# Filename : client.pl

use strict;
use Socket;

# initialize host and port
my $host = shift || 'localhost';
my $port = shift || 7890;
my $server = "localhost";  # Host IP running the server

# create the socket, connect to the port
socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2])
   or die "Can't create a socket $!\n";
connect( SOCKET, pack_sockaddr_in($port, inet_aton($server)))
   or die "Can't connect to port $port! \n";

my $line;
while ($line = <SOCKET>) {
   print "$line\n";
}
close SOCKET or die "close: $!";

Maintenant, démarrons notre client à l'invite de commande, qui se connectera au serveur et lira le message envoyé par le serveur et affichera la même chose à l'écran comme suit -

$perl client.pl
Smile from the server

NOTE - Si vous donnez l'adresse IP réelle en notation par points, il est recommandé de fournir une adresse IP dans le même format à la fois sur le client et sur le serveur pour éviter toute confusion.