Perl - Programmazione socket

Cos'è un socket?

Socket è un meccanismo UNIX di Berkeley per creare una connessione duplex virtuale tra diversi processi. Questo è stato successivamente trasferito su tutti i sistemi operativi noti consentendo la comunicazione tra i sistemi in posizioni geografiche in esecuzione su diversi software del sistema operativo. Se non fosse stato per il socket, la maggior parte della comunicazione di rete tra i sistemi non sarebbe mai avvenuta.

Guardando più da vicino; un tipico sistema informatico su una rete riceve e invia le informazioni desiderate dalle varie applicazioni in esecuzione su di esso. Queste informazioni vengono instradate al sistema, poiché ad esso è designato un indirizzo IP univoco. Sul sistema, queste informazioni vengono fornite alle applicazioni pertinenti, che ascoltano su porte diverse. Ad esempio, un browser Internet ascolta sulla porta 80 le informazioni ricevute dal server web. Inoltre possiamo scrivere le nostre applicazioni personalizzate che possono ascoltare e inviare / ricevere informazioni su un numero di porta specifico.

Per ora, riassumiamo che un socket è un indirizzo IP e una porta, che consente alla connessione di inviare e ricevere dati su una rete.

Per spiegare il concetto di socket sopra menzionato prenderemo un esempio di Programmazione client - server utilizzando Perl. Per completare un'architettura client server dovremmo seguire i seguenti passaggi:

Per creare un server

  • Crea un socket usando socket chiamata.

  • Associare il socket a un indirizzo di porta utilizzando bind chiamata.

  • Ascolta il socket all'indirizzo della porta utilizzando listen chiamata.

  • Accetta le connessioni client utilizzando accept chiamata.

Per creare un cliente

  • Crea un socket con socket chiamata.

  • Connetti (il socket) al server usando connect chiamata.

Il diagramma seguente mostra la sequenza completa delle chiamate utilizzate da Client e Server per comunicare tra loro:

Chiamate socket lato server

La chiamata socket ()

Il socket()chiamata è la prima chiamata che stabilisce una connessione di rete sta creando un socket. Questa chiamata ha la seguente sintassi:

socket( SOCKET, DOMAIN, TYPE, PROTOCOL );

La chiamata precedente crea un SOCKET e altri tre argomenti sono numeri interi che dovrebbero avere i seguenti valori per le connessioni TCP / IP.

  • DOMAINdovrebbe essere PF_INET. È probabile 2 sul tuo computer.

  • TYPE dovrebbe essere SOCK_STREAM per la connessione TCP / IP.

  • PROTOCOL dovrebbe essere (getprotobyname('tcp'))[2]. È il protocollo particolare come TCP ad essere pronunciato sul socket.

Quindi la chiamata alla funzione socket emessa dal server sarà qualcosa del genere:

use Socket     # This defines PF_INET and SOCK_STREAM

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

La chiamata bind ()

I socket creati dalla chiamata socket () sono inutili finché non sono associati a un nome host e un numero di porta. Il server utilizza quanto seguebind() funzione per specificare la porta alla quale accetteranno le connessioni dai client.

bind( SOCKET, ADDRESS );

Qui SOCKET è il descrittore restituito dalla chiamata socket () e ADDRESS è un indirizzo socket (per TCP / IP) contenente tre elementi -

  • La famiglia di indirizzi (per TCP / IP, è AF_INET, probabilmente 2 sul sistema).

  • Il numero di porta (ad esempio 21).

  • L'indirizzo Internet del computer (ad esempio 10.12.12.168).

Poiché bind () è usato da un server, che non ha bisogno di conoscere il proprio indirizzo, quindi l'elenco degli argomenti assomiglia a questo -

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";

Il or die la clausola è molto importante perché se un server muore senza connessioni in sospeso, la porta non sarà immediatamente riutilizzabile a meno che non si usi l'opzione SO_REUSEADDR utilizzando setsockopt()funzione. Quipack_sockaddr_in() viene utilizzata per comprimere la porta e l'indirizzo IP in formato binario.

La chiamata listen ()

Se si tratta di un programma server, è necessario inviare una chiamata a listen()sulla porta specificata per ascoltare, cioè attendere le richieste in arrivo. Questa chiamata ha la seguente sintassi:

listen( SOCKET, QUEUESIZE );

La chiamata precedente utilizza il descrittore SOCKET restituito dalla chiamata socket () e QUEUESIZE è il numero massimo di richieste di connessione in sospeso consentite simultaneamente.

La chiamata accept ()

Se si tratta di un programma server, è necessario inviare una chiamata a access()funzione per accettare le connessioni in entrata. Questa chiamata ha la seguente sintassi:

accept( NEW_SOCKET, SOCKET );

La chiamata di accettazione riceve il descrittore SOCKET restituito dalla funzione socket () e al completamento con successo, viene restituito un nuovo descrittore di socket NEW_SOCKET per tutte le comunicazioni future tra il client e il server. Se la chiamata ad access () fallisce, restituisce FLASE che è definito nel modulo Socket che abbiamo usato inizialmente.

Generalmente, accept () viene utilizzato in un ciclo infinito. Non appena arriva una connessione, il server crea un processo figlio per gestirla o la serve lui stesso e poi torna ad ascoltare altre connessioni.

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

Ora tutte le chiamate relative al server sono terminate e vediamo una chiamata che verrà richiesta dal client.

Chiamate socket lato client

La chiamata connect ()

Se hai intenzione di preparare un programma client, prima utilizzerai socket() call per creare un socket e poi dovresti usare connect()chiamare per connettersi al server. Hai già visto la sintassi della chiamata socket () e rimarrà simile alla chiamata del server socket (), ma ecco la sintassi perconnect() chiamata -

connect( SOCKET, ADDRESS );

Qui SCOKET è il descrittore socket restituito dalla chiamata socket () emessa dal client e ADDRESS è un indirizzo socket simile alla chiamata bind , tranne per il fatto che contiene l'indirizzo IP del server remoto.

$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";

Se ti connetti al server con successo, puoi iniziare a inviare i tuoi comandi al server usando il descrittore SOCKET, altrimenti il ​​tuo client uscirà dando un messaggio di errore.

Client - Esempio di server

Di seguito è riportato un codice Perl per implementare un semplice programma client-server utilizzando Perl socket. Qui il server ascolta le richieste in arrivo e una volta stabilita la connessione, risponde semplicemente a Smile dal server . Il client legge quel messaggio e stampa sullo schermo. Vediamo come è stato fatto, supponendo di avere il nostro server e client sulla stessa macchina.

Script per creare un server

#!/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;
}

Per eseguire il server in modalità background, immetti il ​​seguente comando sul prompt di Unix:

$perl sever.pl&

Script per creare 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: $!";

Ora avviamo il nostro client al prompt dei comandi, che si connetterà al server e leggerà il messaggio inviato dal server e visualizzerà lo stesso sullo schermo come segue:

$perl client.pl
Smile from the server

NOTE - Se si fornisce l'indirizzo IP effettivo in notazione a punti, si consiglia di fornire l'indirizzo IP nello stesso formato sia nel client che nel server per evitare qualsiasi confusione.