Programación básica de sockets en Python

En general, los servicios de red siguen el modelo tradicional cliente/servidor. Una computadora actúa como un servidor para proporcionar un determinado servicio y otra computadora representa...

En general, los servicios de red siguen el modelo tradicional cliente/servidor. Una computadora actúa como un servidor para proporcionar un determinado servicio y otra computadora representa el lado del cliente que hace uso de este servicio. Para comunicarse a través de la red, entra en juego un toma de red, generalmente conocido como socket. Este tipo de comunicación de socket puede incluso usarse internamente en una computadora para [comunicación entre procesos] (https://en.wikipedia.org/wiki/Inter-process_communication) (IPC).

Este artículo explica cómo escribir una aplicación cliente/servidor simple que se comunica a través de un socket de red utilizando el lenguaje de programación Python. Para simplificar, nuestro servidor de ejemplo solo envía los datos recibidos a la salida estándar. La idea detrás de la aplicación cliente/servidor es un sensor en una estación meteorológica, que recopila datos de temperatura a lo largo del tiempo y los envía a una aplicación de servidor, donde los datos se procesan aún más.

¿Qué es un zócalo?

Un socket de red es un punto final de un enlace de comunicación bidireccional entre dos programas o procesos (cliente y servidor en nuestro caso) que se ejecutan en la red. Esto puede ser en la misma computadora, así como en diferentes sistemas que están conectados a través de la red.

Ambas partes se comunican entre sí escribiendo o leyendo desde el socket de la red. El equivalente técnico en realidad es una comunicación telefónica entre dos participantes. El enchufe de red representa el número correspondiente de la línea telefónica, o un contrato en el caso de teléfonos celulares.

Ejemplo

Para hacer uso de la funcionalidad de socket, solo es necesario el Python módulo de enchufe. En el código de ejemplo que se muestra a continuación, también se importa el módulo de tiempo de Python para simular la estación meteorológica y simplificar los cálculos de tiempo.

En este caso, tanto el cliente como el servidor se ejecutan en la misma computadora. Un socket tiene un número de puerto correspondiente, que es 23456 en nuestro caso. Si lo desea, puede elegir un número de puerto diferente del rango de números sin restricciones entre 1024 y 65535.

El servidor

Después de cargar el módulo socket adicional de Python, se crea un socket de transmisión de Internet usando la clase socket.socket con los dos parámetros socket.AF_INET y socket.SOCK_STREAM. La recuperación del nombre de host, el nombre de dominio completo y la dirección IP se realiza mediante los métodos gethostname(), getfqdn() y gethostbyname(), respectivamente. A continuación, el socket está vinculado a la dirección IP y al número de puerto 23456 con la ayuda del método bind().

Con la ayuda del método listen(), el servidor escucha las conexiones entrantes en el puerto especificado. En el bucle while, el servidor espera las solicitudes entrantes y las acepta utilizando el método accept(). Los datos enviados por el cliente se leen a través del método recv() como fragmentos de 64 bytes, y simplemente se envían a la salida estándar. Finalmente, la conexión actual se cierra si no se envían más datos desde el cliente.

 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
47
48
# load additional Python module
import socket

# create TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# retrieve local hostname
local_hostname = socket.gethostname()

# get fully qualified hostname
local_fqdn = socket.getfqdn()

# get the according IP address
ip_address = socket.gethostbyname(local_hostname)

# output hostname, domain name and IP address
print ("working on %s (%s) with %s" % (local_hostname, local_fqdn, ip_address))

# bind the socket to the port 23456
server_address = (ip_address, 23456)
print ('starting up on %s port %s' % server_address)
sock.bind(server_address)

# listen for incoming connections (server mode) with one connection at a time
sock.listen(1)

while True:
    # wait for a connection
    print ('waiting for a connection')
    connection, client_address = sock.accept()

    try:
        # show who connected to us
        print ('connection from', client_address)

        # receive the data in small chunks and print it
        while True:
            data = connection.recv(64)
            if data:
                # output received data
                print ("Data: %s" % data)
            else:
                # no more data -- quit the loop
                print ("no more data.")
                break
    finally:
        # Clean up the connection
        connection.close()

El Cliente

Ahora vamos a echar un vistazo al lado del cliente. El código de Python es en su mayoría similar al del lado del servidor, excepto por el uso del zócalo; en su lugar, el cliente usa el método connect(). En un bucle for, los datos de temperatura se envían al servidor mediante el método sendall(). La llamada del método time.sleep(2) detiene al cliente durante dos segundos antes de enviar otra lectura de temperatura. Después de enviar todos los datos de temperatura de la lista, la conexión finalmente se cierra usando el método close().

 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
# load additional Python modules
import socket
import time

# create TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# retrieve local hostname
local_hostname = socket.gethostname()

# get fully qualified hostname
local_fqdn = socket.getfqdn()

# get the according IP address
ip_address = socket.gethostbyname(local_hostname)

# bind the socket to the port 23456, and connect
server_address = (ip_address, 23456)
sock.connect(server_address)
print ("connecting to %s (%s) with %s" % (local_hostname, local_fqdn, ip_address))

# define example data to be sent to the server
temperature_data = ["15", "22", "21", "26", "25", "19"]
for entry in temperature_data:
    print ("data: %s" % entry)
    new_data = str("temperature: %s\n" % entry).encode("utf-8")
    sock.sendall(new_data)
    
    # wait for two seconds
    time.sleep(2)

# close connection
sock.close()

Ejecutar el servidor y el cliente

Para ejecutar tanto el servidor como el programa cliente, abra dos ventanas de terminal y emita los siguientes comandos, uno por ventana de terminal y en el siguiente orden:

1
$ python3 echo-server.py

y

1
$ python3 echo-client.py

Las dos figuras siguientes muestran la salida correspondiente del programa de ejemplo:

Comunicación del socket del servidor en Python{.img-responsive}

_Figura 1_

Comunicación de socket de cliente en Python{.img-responsive}

_Figura 2_

Conclusión

Escribir programas Python que usan IPC con sockets es bastante simple. El ejemplo anterior ciertamente se puede extender para manejar algo más complejo. Para obtener más información y métodos adicionales, puede consultar algunos excelentes [Recursos de programación de socket de Python] (http://stackabu.se/foundations-of-python-network-programming) disponibles. es.