Perl - Programación de sockets

¿Qué es un enchufe?

Socket es un mecanismo UNIX de Berkeley para crear una conexión dúplex virtual entre diferentes procesos. Más tarde, esto se trasladó a todos los sistemas operativos conocidos, lo que permite la comunicación entre sistemas en ubicaciones geográficas que se ejecutan en diferentes software de sistemas operativos. Si no fuera por el zócalo, la mayor parte de la comunicación de red entre sistemas nunca hubiera ocurrido.

Echando un vistazo más de cerca; un sistema informático típico en una red recibe y envía información según lo deseado por las diversas aplicaciones que se ejecutan en él. Esta información se envía al sistema, ya que se le asigna una dirección IP única. En el sistema, esta información se proporciona a las aplicaciones relevantes, que escuchan en diferentes puertos. Por ejemplo, un navegador de Internet escucha en el puerto 80 la información recibida del servidor web. También podemos escribir nuestras aplicaciones personalizadas que pueden escuchar y enviar / recibir información en un número de puerto específico.

Por ahora, resumamos que un socket es una dirección IP y un puerto, lo que permite que la conexión envíe y reciba datos a través de una red.

Para explicar el concepto de socket mencionado anteriormente, tomaremos un ejemplo de Programación Cliente - Servidor usando Perl. Para completar la arquitectura de un servidor cliente tendríamos que seguir los siguientes pasos:

Para crear un servidor

  • Crea un socket usando socket llamada.

  • Vincular el socket a una dirección de puerto usando bind llamada.

  • Escuche el conector en la dirección del puerto usando listen llamada.

  • Acepte conexiones de cliente usando accept llamada.

Para crear un cliente

  • Crea un enchufe con socket llamada.

  • Conecte (el enchufe) al servidor usando connect llamada.

El siguiente diagrama muestra la secuencia completa de las llamadas utilizadas por el Cliente y el Servidor para comunicarse entre sí:

Llamadas de socket del lado del servidor

La llamada socket ()

los socket()La llamada es la primera llamada para establecer una conexión de red y es crear un enchufe. Esta llamada tiene la siguiente sintaxis:

socket( SOCKET, DOMAIN, TYPE, PROTOCOL );

La llamada anterior crea un SOCKET y los otros tres argumentos son números enteros que deben tener los siguientes valores para las conexiones TCP / IP.

  • DOMAINdebe ser PF_INET. Es probable que haya 2 en su computadora.

  • TYPE debe ser SOCK_STREAM para la conexión TCP / IP.

  • PROTOCOL debiera ser (getprotobyname('tcp'))[2]. Es el protocolo particular, como TCP, que se habla a través del socket.

Entonces, la llamada a la función de socket emitida por el servidor será algo como esto:

use Socket     # This defines PF_INET and SOCK_STREAM

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

La llamada bind ()

Los sockets creados por la llamada socket () son inútiles hasta que están vinculados a un nombre de host y un número de puerto. El servidor utiliza lo siguientebind() función para especificar el puerto en el que aceptarán conexiones de los clientes.

bind( SOCKET, ADDRESS );

Aquí SOCKET es el descriptor devuelto por la llamada socket () y ADDRESS es una dirección de socket (para TCP / IP) que contiene tres elementos:

  • La familia de direcciones (para TCP / IP, es AF_INET, probablemente 2 en su sistema).

  • El número de puerto (por ejemplo, 21).

  • La dirección de Internet de la computadora (por ejemplo, 10.12.12.168).

Como un servidor usa bind (), que no necesita saber su propia dirección, la lista de argumentos se ve así:

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

los or die La cláusula es muy importante porque si un servidor muere sin conexiones pendientes, el puerto no será inmediatamente reutilizable a menos que use la opción SO_REUSEADDR usando setsockopt()función. aquípack_sockaddr_in() se está utilizando la función para empaquetar el puerto y la dirección IP en formato binario.

La llamada listen ()

Si se trata de un programa de servidor, es necesario realizar una llamada a listen()en el puerto especificado para escuchar, es decir, esperar las solicitudes entrantes. Esta llamada tiene la siguiente sintaxis:

listen( SOCKET, QUEUESIZE );

La llamada anterior usa el descriptor SOCKET devuelto por la llamada socket () y QUEUESIZE es el número máximo de solicitudes de conexión pendientes permitidas simultáneamente.

La llamada accept ()

Si se trata de un programa de servidor, es necesario realizar una llamada al access()función para aceptar las conexiones entrantes. Esta llamada tiene la siguiente sintaxis:

accept( NEW_SOCKET, SOCKET );

El descriptor de aceptar llamada recibir SOCKET devuelto por la función socket () y una vez completado con éxito, se devuelve un nuevo descriptor de socket NEW_SOCKET para todas las comunicaciones futuras entre el cliente y el servidor. Si la llamada a access () falla, devuelve FLASE, que se define en el módulo Socket que hemos utilizado inicialmente.

Generalmente, accept () se usa en un bucle infinito. Tan pronto como llega una conexión, el servidor crea un proceso hijo para tratar con ella o la sirve él mismo y luego regresa para escuchar más conexiones.

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

Ahora todas las llamadas relacionadas con el servidor han terminado y veamos una llamada que será requerida por el cliente.

Llamadas de socket del lado del cliente

La llamada connect ()

Si va a preparar el programa del cliente, primero utilizará socket() llamar para crear un socket y luego tendrías que usar connect()llamar para conectarse al servidor. Ya ha visto la sintaxis de llamada a socket () y seguirá siendo similar a la llamada del servidor socket (), pero aquí está la sintaxis deconnect() llamar -

connect( SOCKET, ADDRESS );

Aquí SCOKET es el descriptor de socket devuelto por la llamada socket () emitida por el cliente y ADDRESS es una dirección de socket similar a la llamada de enlace , excepto que contiene la dirección IP del servidor 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";

Si se conecta al servidor correctamente, puede comenzar a enviar sus comandos al servidor utilizando el descriptor SOCKET; de lo contrario, su cliente saldrá con un mensaje de error.

Cliente - Ejemplo de servidor

A continuación se muestra un código Perl para implementar un programa cliente-servidor simple usando un socket Perl. Aquí el servidor escucha las solicitudes entrantes y una vez que se establece la conexión, simplemente responde Smile desde el servidor . El cliente lee ese mensaje y lo imprime en la pantalla. Veamos cómo se ha hecho, asumiendo que tenemos nuestro servidor y cliente en la misma máquina.

Script para crear un servidor

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

Para ejecutar el servidor en modo de fondo, ejecute el siguiente comando en el indicador de Unix:

$perl sever.pl&

Script para crear un cliente

!/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: $!";

Ahora iniciemos nuestro cliente en el símbolo del sistema, que se conectará al servidor y leerá el mensaje enviado por el servidor y mostrará el mismo en la pantalla de la siguiente manera:

$perl client.pl
Smile from the server

NOTE - Si proporciona la dirección IP real en notación de puntos, se recomienda proporcionar la dirección IP en el mismo formato tanto en el cliente como en el servidor para evitar confusiones.