Programación de sockets en Python: una guía para principiantes

Aditya Raj 10 octubre 2023
  1. Cómo implementar la programación de sockets en Python
  2. Cómo crear un servidor en la programación de sockets en Python
  3. Programación de sockets con el protocolo UDP en Python
  4. Conclusión
Programación de sockets en Python: una guía para principiantes

Normalmente, cuando escribimos un programa, no necesitamos comunicarnos con otros programas o computadoras.

Sin embargo, es posible que necesitemos comunicarnos con otras computadoras para crear aplicaciones de mensajería u otras aplicaciones con arquitectura servidor-cliente. Para crear tales aplicaciones, podemos usar la programación de sockets en Python.

Este artículo discutirá los conceptos básicos de la programación de sockets en Python. También implementaremos por separado una aplicación de mensajería simple utilizando la programación de socket con los protocolos TCP y UDP.

¿Qué son los sockets en Python?

Cuando dos aplicaciones o procesos interactúan, utilizan un canal de comunicación específico. Los sockets son los puntos finales o puntos de entrada de dichos canales de comunicación.

Podemos usar sockets para establecer un canal de comunicación entre dos procesos, dentro de un proceso o entre procesos en diferentes máquinas. Hay diferentes tipos de sockets como sockets TCP, sockets UDP y sockets de dominio UNIX.

Cómo implementar la programación de sockets en Python

Python nos proporciona el módulo socket para implementar la programación de sockets. El módulo socket es parte de la biblioteca estándar de Python y proporciona todas las funciones y métodos con la ayuda de los cuales puede crear sockets en Python.

No necesita descargar explícitamente el módulo socket en su máquina, y puede importarlo directamente a su programa usando la declaración de importación de la siguiente manera.

import socket

Para implementar la programación de socket, necesitamos crear dos procesos que se comunicarán usando el socket.

Uno de los programas funciona como servidor y el otro funciona como cliente. Tanto el servidor como el cliente tienen diferentes funcionalidades. Por lo tanto, usamos diferentes funciones al crear procesos de servidor y cliente.

Analicemos cómo crear un servidor y un proceso de cliente uno por uno.

Cómo crear un servidor en la programación de sockets en Python

Para crear un servidor, primero crearemos un socket. Para ello utilizamos el método socket().

Crear un socket: el método socket()

La sintaxis del método socket() es la siguiente.

socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, fileno=None)

Aquí,

  • El parámetro familia representa la familia de direcciones a la que pertenece un socket. Por defecto, es AF_INET y crea un socket con una dirección de protocolo de Internet versión 4 (IPv4). Puede utilizar otras familias de direcciones como AF_UNIX para la dirección UNIX y AF_INET6 para la dirección del protocolo de Internet versión 6 (IPv6).
  • El parámetro type denota el tipo de socket. Por defecto, tiene el valor SOCK_STREAM denotando que el socket seguirá el protocolo TCP orientado a la conexión. Puedes utilizar SOCK_DGRAM para crear sockets de datagramas que sigan el protocolo UDP.
  • El parámetro proto denota el número de protocolo, y normalmente es 0. Si utiliza la familia de direcciones AF_CAN en la familia de parámetros, el número de protocolo debe ser uno de CAN_RAW, CAN_BCM, CAN_ISOTP, o CAN_J1939.
  • El parámetro fileno contiene el valor por defecto None. Si especificamos un descriptor de fichero en fileno, los valores de los parámetros family, type, y proto se detectan automáticamente a partir del descriptor de fichero.

Después de crear un socket, lo vinculamos a una dirección y un número de puerto usando el método bind().

Vincular el socket a una dirección: el método bind()

Usando la función socket(), el método bind() se invoca en el objeto socket que creamos.

Toma una tupla que contiene la dirección a la que se vinculará el socket. El formato de la dirección puede variar según la familia de direcciones que haya elegido. Crearemos un socket con la familia de direcciones AF_INET. Por lo tanto, la dirección contendrá el nombre de host y el número de puerto.

La sintaxis del método bind() es la siguiente.

bind((hostname, port))

Puede especificar el nombre de host explícitamente. Si crea el servidor en la máquina local, puede especificar el nombre de host como localhost o 127.0.0.1, el valor predeterminado para la dirección localhost.

Alternativamente, puede usar el método gethostname() para obtener el nombre de host. Para el parámetro puerto, puede utilizar cualquier número de puerto superior a 1024 e inferior a 65535.

Después de vincular el socket a una dirección, el servidor escucha las solicitudes de conexión del cliente. Para ello utilizamos el método listen().

Escuche las conexiones: el método listen()

La sintaxis del método listen() es la siguiente.

listen(backlog)

Aquí, el parámetro backlog indica el número máximo de conexiones no aceptadas que el sistema permitirá antes de rechazar nuevas conexiones.

Después de ejecutar el método listen(), el servidor está listo para aceptar conexiones.

Aceptar una solicitud de conexión: el método aceptar()

El servidor se ejecuta constantemente en un bucle infinito y escucha las solicitudes de los clientes para aceptar una conexión de un cliente. Una vez que se encuentra una solicitud de cliente, el servidor acepta la solicitud utilizando el método aceptar().

El método aceptar() devuelve una tupla (cliente, dirección). Aquí, cliente representa un nuevo objeto socket que usamos para enviar y recibir mensajes. La dirección es donde está vinculado el socket del cliente.

Comunicación con el Cliente: Métodos send() y recv()

Después de aceptar la conexión, el servidor puede comunicarse con el cliente.

Usamos el método send() para enviar un mensaje al cliente. El método send() se invoca sobre el objeto client devuelto por el método aceptar().

Usamos el método recv() para recibir los mensajes. El método recv(), cuando se invoca en el objeto client, acepta un número que representa el número máximo de bytes que puede leer de la conexión. Después de la ejecución, devuelve los datos leídos de la conexión.

Una vez completadas todas las operaciones, debemos cerrar la conexión. Para ello, invocamos el método close() sobre el objeto client devuelto por el método accept().

Habiendo discutido todos los métodos requeridos para crear un servidor, creemos un proceso de servidor.

import socket

mySocket = socket.socket(
    family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, fileno=None
)
print("Socket created.")
hostname = "localhost"
portno = 9999
mySocket.bind((hostname, portno))
print("Socket bound to address {} and port number {}".format(hostname, portno))
mySocket.listen(5)
print("Listening for client.")
while True:
    client, client_addr = mySocket.accept()
    print("Connection established with client at address {}".format(client_addr))
    msg = client.recv(1024).decode()
    print("Message received from the client:")
    print(msg)
    print("Sending acknowledgment to the client.")
    msg_out = "Message received: {}. Thank you.".format(msg).encode()
    client.send(msg_out)
    print("Terminating the connection.")
    client.close()
    break

Ahora que hemos creado un servidor, creemos un proceso de cliente que se comunicará con el servidor.

Cómo crear un cliente en la programación de sockets

Para crear un cliente, primero necesitamos crear un socket con el método socket() como lo hicimos al crear el servidor. Recuerde que los protocolos definidos para el socket del cliente deben ser los mismos que los del socket del servidor. De lo contrario, el programa no funcionará como se desea.

Después de crear el socket, necesitamos conectarlo al servidor. Para ello, utilizaremos el método connect().

Conectarse al Servidor: El Método connect()

La sintaxis del método connect() es la siguiente.

connect((host, port))

Aquí, el parámetro host denota la dirección del servidor. El parámetro port indica el número de puerto en el que se crea el socket del servidor. Debe dar los mismos valores como entrada al host y al parámetro de puerto que proporcionó al método bind() al crear el servidor.

Comunicación con el servidor

Después de conectarse al servidor, puede comunicarse con el servidor utilizando los métodos send() y recv(). Finalmente, ayudaría a cerrar la conexión desde el lado del cliente utilizando el método close().

El siguiente es el programa cliente que usaremos para crear un proceso cliente.

import socket

mySocket = socket.socket(
    family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, fileno=None
)
print("Socket created.")
hostname = "localhost"
portno = 9999
mySocket.connect((hostname, portno))
print("Connection established with the server.")
msg = "Hi I am a TCP client created by Aditya."
print("Sending msg to the server:", msg)
mySocket.send(msg.encode())
msg_in = mySocket.recv(1024).decode()
print("Acknowledgment received from the server:")
print(msg_in)
print("Terminating the Connection.")
mySocket.close()

Habiendo creado el servidor y el cliente, ahora ejecutemos los programas. Recuerde que debe ejecutar tanto el programa del cliente como el programa del servidor simultáneamente para que ambos procesos puedan estar activos simultáneamente y comunicarse entre sí.

La salida en la terminal con el programa del servidor se verá así:

Socket created.
Socket bound to address localhost and port number 9999
Listening for client.
Connection established with client at address ('127.0.0.1', 37958)
Message received from the client:
Hi I am a TCP client created by Aditya.
Sending acknowledgment to the client.
Terminating the connection.

La salida en la terminal con el programa cliente se verá así:

Socket created.
Connection established with the server.
Sending msg to the server: Hi I am a TCP client created by Aditya.
Acknowledgment received from the server:
Message received: Hi I am a TCP client created by Aditya.. Thank you.
Terminating the Connection.

Programación de sockets con el protocolo UDP en Python

En las secciones anteriores, hemos creado sockets que siguen el protocolo TCP en la conexión. En el protocolo TCP, la conexión entre el cliente y el servidor se mantiene durante toda la comunicación.

Sin embargo, hay muchas situaciones en las que no podemos mantener una conexión estable entre el cliente y el servidor debido a limitaciones de recursos. Por lo tanto, necesitamos un protocolo de comunicación que no requiera una conexión estable. Para ello utilizamos el protocolo UDP.

Cómo crear un servidor con protocolo UDP en Python

Para crear una conexión con el protocolo UDP, debemos seguir los siguientes pasos mientras implementamos el servidor.

  • Especifique SOCK_DGRAM en la entrada del parámetro de tipo al crear el socket del servidor con el método socket().
  • Vincule el socket a una dirección y un número de puerto utilizando el método bind().
  • Como no necesitamos establecer una conexión con el cliente, no usamos los métodos listen() y accept() para establecer la conexión. Directamente podemos empezar a comunicarnos con el cliente.
  • Para recibir un mensaje en el protocolo UDP, usamos el método recvfrom(). Toma el número de bytes para leer como argumento de entrada y devuelve una tupla que contiene los datos y la dirección desde la que se han recibido los datos.
  • Para enviar un mensaje en el protocolo UDP, usamos el método sendto(). El método sendto() toma los datos como su primer argumento de entrada y una tupla que contiene el nombre de host y el número de puerto como la dirección del socket al que se enviarán los datos.
  • Después de la comunicación, debe cerrar el socket utilizando el método close().

Usando el siguiente programa de Python, puede implementar un proceso de servidor que se comunica con el protocolo UDP.

import socket

mySocket = socket.socket(
    family=socket.AF_INET, type=socket.SOCK_DGRAM, proto=0, fileno=None
)
print("Socket created.")
hostname = "localhost"
portno = 9999
mySocket.bind((hostname, portno))
print("Socket bound to address {} and port number {}".format(hostname, portno))
while True:
    msg, client_addr = mySocket.recvfrom(1024)
    print("Message received from the client:")
    print(msg.decode())
    print("Sending acknowledgment to the client.")
    msg_out = "Message received: {}. Thank you.".format(msg).encode()
    mySocket.sendto(msg_out, client_addr)
    mySocket.close()
    break

Cómo crear un cliente con protocolo UDP en Python

Para crear un proceso de cliente que siga el protocolo UDP, necesitamos crear el socket especificando SOCK_DGRAM en la entrada del parámetro de tipo mientras creamos el socket del servidor con el método socket(). No necesitamos usar el método connect() aquí ya que no tenemos que crear una conexión.

Después de crear el socket, podemos comenzar a comunicarnos directamente con el servidor usando los métodos sendto() y recvfrom(). Después de comunicarte con el servidor, no olvides cerrar el socket usando el método close().

Usando el siguiente programa de Python, puede implementar un proceso de cliente que se comunica con el protocolo UDP.

import socket

mySocket = socket.socket(
    family=socket.AF_INET, type=socket.SOCK_DGRAM, proto=0, fileno=None
)
print("Socket created.")
while True:
    msg = "Hi I am a UDP client created by Aditya."
    print("Sending msg to the server:", msg)
    mySocket.sendto(msg.encode(), ("localhost", 9999))
    msg_in = mySocket.recv(1024).decode()
    print("Acknowledgment received from the server:")
    print(msg_in)
    print("Terminating the Connection.")
    mySocket.close()
    break

Una vez más, para observar el resultado, debe ejecutar tanto el programa del cliente como el programa del servidor simultáneamente para que ambos procesos puedan estar activos al mismo tiempo y puedan comunicarse entre sí.

La salida en la terminal con el programa del servidor se verá así:

Socket created.
Socket bound to address localhost and port number 9999
Message received from the client:
Hi I am a UDP client created by Aditya.
Sending acknowledgment to the client.

La salida en la terminal con el programa cliente se verá así:

Socket created.
Sending msg to the server: Hi I am a UDP client created by Aditya.
Acknowledgment received from the server:
Message received: b'Hi I am a UDP client created by Aditya.'. Thank you.
Terminating the Connection.

Conclusión

En este artículo, hemos discutido la programación de sockets en Python. También hemos implementado programas de cliente y servidor por separado utilizando los protocolos TCP y UDP para aprender los conceptos básicos de la programación de sockets en Python.

TCP está orientado a la conexión y, por lo tanto, es un protocolo confiable. Al usar el protocolo TCP, se garantiza que los mensajes llegarán del servidor al cliente y viceversa. En UDP, no se garantiza que el mensaje se entregue al destino deseado.

Por otro lado, el protocolo UDP es más rápido y fácil de implementar, mientras que el protocolo TCP es más lento. Además, el protocolo TCP no se puede usar para la transmisión, mientras que podemos usar el protocolo UDP para la transmisión.

Según los recursos disponibles y su necesidad, puede elegir cualquier protocolo para implementar la comunicación cliente-servidor mediante sockets.

Autor: Aditya Raj
Aditya Raj avatar Aditya Raj avatar

Aditya Raj is a highly skilled technical professional with a background in IT and business, holding an Integrated B.Tech (IT) and MBA (IT) from the Indian Institute of Information Technology Allahabad. With a solid foundation in data analytics, programming languages (C, Java, Python), and software environments, Aditya has excelled in various roles. He has significant experience as a Technical Content Writer for Python on multiple platforms and has interned in data analytics at Apollo Clinics. His projects demonstrate a keen interest in cutting-edge technology and problem-solving, showcasing his proficiency in areas like data mining and software development. Aditya's achievements include securing a top position in a project demonstration competition and gaining certifications in Python, SQL, and digital marketing fundamentals.

GitHub

Artículo relacionado - Python Socket

Artículo relacionado - Python Module