Bienvenidos nuevamente a este blog sobre programación en lenguaje Python. En esta ocasión os traemos un primer artículo acerca de la programación en Python usando sockets. Concretamente, lo que haremos será establecer una primera comunicación en la que un servidor recibirá una petición de conexión por parte de un cliente, y una vez establecida esta, devolverá una información a este último.
QUÉ SON LOS SOCKETS.
Para empezar, diremos que la programación con sockets, lo que pretende es el establecimiento de una conexión o comunicación de red (cliente–servidor) entre dos nodos en los cuales vamos a tener código de Python en ejecución. Dicha conexión la estableceremos a partir de una dirección de red que determinará el destino y origen de la comunicación, y un puerto que definirá el medio o camino por el que se va a trasmitir dicha información.
En el transcurso de dicho proceso de conexión, tanto en el lado del servidor como en el del cliente, van a ejecutarse una serie de métodos cuyo flujo y relaciones, pueden contemplarse en el siguiente diagrama:

Tenemos aquí un servidor que empieza creando una puerta de entrada-salida de información a través de una dirección IP y un puerto que asociará con esta mediante el método «bind()«. Una vez creada dicha asociación pondrá el socket en modo escucha a través del método «listen()«, dejando el socket, mediante «accept()» a la espera de recibir alguna solicitud de conexión por parte del cliente, el cual, tras haber igualmente creado su correspondiente socket a partir de una IP y un puerto, realizará dicha solicitud al servidor, usando el método «connect()«. Una vez aceptada dicha solicitud por el servidor, ambos entrarán en una fase en la que podrán mutuamente, recibir y mandarse información, usando los métodos «recv()» y «send()» respectivamente.
CODIFICACIÓN EN PYTHON.
Visto someramente el modo en que se establece la conexión cliente–servidor, es hora de hacer nuestra simulación de conexión en Python. Para lo cual, crearemos dos archivos «server.py» y «client.py» que ejecutarán las acciones vistas anteriormente tanto de un lado como del otro.
Lo que haremos ahora, es crear un servidor que pondremos a la espera de recibir una solicitud de conexión por parte de un cliente. De modo que cuando esta se produzca, mostrará un mensaje de conexión establecida recibiendo una información de dicho cliente, que después devolverá a este. Para ello, como ya hemos dicho, crearemos dos scripts que simularán a ambas partes de la conexión, empezando por el servidor:

Como se ve, empezamos importando el módulo «socket» para poder trabajar con estas conexiones, tras lo cual, pasaremos a definir la dirección en la que se ejecuta nuestro servidor. Puesto que el servidor se va a ejecutar en nuestro equipo, usaremos el host 127.0.0.1 que es el correspondiente al host local (la misma auto referencia conseguiremos introduciendo «localhost» en su lugar). Acto seguido definiremos el puerto a través del cual se producirá dicha conexión. Definidos tales parámetros, (y con estos) pasamos a iniciar el socket, asociando dicha información al mismo usando el método «bind()» para a continuación, empleando el método «listen()«, ponerlo en modo escucha, a la espera de posibles solicitudes de conexión entrantes, que captaremos con el método «accept()» el cual nos devolverá dos valores: la conexión entrante (que guardaremos en la variable «conn«) y la dirección IP de procedencia (que se guardará en la variable «addr«). Una vez establecida la conexión, usaremos el método «recv()» (en el que especificaremos la cantidad, en bytes, de información, que podrá recibir el servidor) para obtener la información del cliente, la cual a continuación devolveremos a este, usando esta vez, el método «sendall()«.
Visto, el código de nuestro servidor, pasemos ahora a ver el del cliente, que como cabe de esperar viendo el diagrama expuesto más arriba, tiene una codificación más simple:

En este caso, después de la pertinente importación del módulo «socket«, pasamos a definir la dirección IP de destino, la cual, (dado el hecho que en este caso, tanto el servidor como el cliente se ejecutan en la misma máquina) será la misma que en el caso anterior. A su vez, por razones obvias, el puerto (que es el canal de comunicación entre ambas partes) también será el mismo. Una vez que tenemos definida la conexión, abrimos el socket ejecutando el método «connect()» que enviará una solicitud de conexión al servidor, quedando mientras a la espera de ser aceptada por este. Una vez que se consiga la conexión, con el método «sendall()» mandaremos un mensaje a dicho servidor, el cual, a su vez, se lo devolverá al cliente, recibiéndolo este mediante el método «recv()» para mostrarlo nuevamente en su terminal.
EJECUTANDO PRUEBA.
Una vez que tenemos escritos nuestros scripts, pasaremos a ejecutarlos. Para ello, deberemos abrir dos terminales de nuestro CMD, de modo que en uno de ellos ejecutaremos el archivo «server.py«:

Hecho esto, veremos como nuestro servidor, quedará a la espera de recibir alguna solicitud de conexión. Dicha solicitud la efectuaremos ejecutando «client.py» en el otro terminal que tendremos abierto:

Vemos como al ejecutar nuestro cliente este recibe por parte del servidor el mensaje que le hemos mandado y que este ha recibido, después de mostrar el mensaje de conexión establecida:

Y hasta aquí este sencillo ejercicio en el que hemos procedido a establecer nuestra primera conexión cliente–servidor realizando nuestra primera transferencia de datos entre ambos usando sockets con Python. En este caso, solo hemos transmitido un sencillo texto en formato bytes, pero en futuras entregas realizaremos operaciones más interesantes como puede ser la transferencia de archivos entre ambos. De todos modos este es un buen comienzo a partir del cual podremos empezar a realizar nuestras propias pruebas y experimentos para proyectos más ambiciosos.
En los siguientes enlaces tenéis el acceso al código tanto del archivo «server.py» como al de «client.py«:
https://github.com/antonioam82/ejercicios-python/blob/master/server.py
https://github.com/antonioam82/ejercicios-python/blob/master/client.py






