¿Cómo enviar y recibir mensajes usando sockets en Python?

PythonBeginner
Practicar Ahora

Introducción

Los sockets de Python ofrecen una herramienta poderosa para la comunicación en red, permitiéndote enviar y recibir mensajes a través de diferentes sistemas. En este tutorial, te guiaremos a través del proceso de uso de sockets de Python para establecer conexiones, transmitir datos y recibir respuestas. Al final de este laboratorio, habrás construido tanto una aplicación cliente como servidor que pueden comunicarse entre sí a través de una red.

Este conocimiento práctico forma la base para el desarrollo de aplicaciones en red más complejas, desde programas de chat hasta sistemas distribuidos.

Entendiendo los Fundamentos de los Sockets y Creando tu Primer Socket

Comencemos por entender qué son los sockets y cómo funcionan en Python. Luego crearemos nuestro primer socket para ver cómo se inicializa.

¿Qué son los Sockets de Python?

Los sockets son puntos finales para enviar y recibir datos a través de una red. Proporcionan una interfaz de programación para la comunicación en red, permitiendo que las aplicaciones intercambien información independientemente de su ubicación.

En la programación de red, normalmente usamos un modelo cliente-servidor:

  • El servidor espera conexiones entrantes y procesa las solicitudes
  • El cliente inicia la comunicación conectándose al servidor

El módulo socket incorporado de Python facilita el trabajo con sockets sin necesidad de entender todos los detalles complejos de los protocolos de red.

Tipos de Sockets

Los dos tipos de socket más comunes son:

  • TCP (Transmission Control Protocol): Proporciona una entrega de datos confiable y ordenada
  • UDP (User Datagram Protocol): Proporciona una transmisión de datos más rápida pero no confiable

Para este laboratorio, nos centraremos en los sockets TCP, que son el tipo más comúnmente utilizado para aplicaciones que requieren comunicación confiable.

Creando tu Primer Socket

Creemos un script de Python simple para inicializar un socket. Abre el WebIDE y sigue estos pasos:

  1. Primero, creemos un directorio para nuestro proyecto de programación de sockets:
mkdir -p ~/project/socket_lab
cd ~/project/socket_lab
  1. Ahora, crea un nuevo archivo Python llamado socket_basics.py:

En el WebIDE, haz clic en el botón "New File" o usa el menú "File" y selecciona "New File", luego nómbralo socket_basics.py dentro del directorio socket_lab.

  1. Agrega el siguiente código para demostrar cómo crear un socket:
import socket

## Creating a socket
print("Creating a new socket...")
my_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print(f"Socket created: {my_socket}")

## Explaining the parameters:
print("\nSocket parameters explained:")
print("AF_INET: Using IPv4 addressing")
print("SOCK_STREAM: Using TCP protocol for reliable data transmission")

## Getting available socket methods
print("\nSome methods available on socket objects:")
methods = [method for method in dir(my_socket) if not method.startswith('_')]
print(', '.join(methods[:10]) + '...')  ## Showing first 10 methods

## Closing the socket
my_socket.close()
print("\nSocket closed")
  1. Guarda el archivo.

  2. Ejecuta el script para ver la salida:

python3 ~/project/socket_lab/socket_basics.py

Deberías ver una salida similar a esta:

Creating a new socket...
Socket created: <socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('0.0.0.0', 0)>

Socket parameters explained:
AF_INET: Using IPv4 addressing
SOCK_STREAM: Using TCP protocol for reliable data transmission

Some methods available on socket objects:
accept, bind, close, connect, connect_ex, detach, fileno, getpeername, getsockname, getsockopt...

Socket closed

Esta salida muestra que hemos creado con éxito un objeto socket y explorado algunas de sus propiedades. En las siguientes secciones, usaremos sockets para construir una aplicación de servidor y cliente que pueda comunicarse entre sí.

Funciones Clave de los Sockets

Antes de continuar, entendamos algunas funciones clave de los sockets que usaremos:

  • socket() - Crea un nuevo objeto socket
  • bind() - Asocia el socket con una interfaz de red y un puerto específicos
  • listen() - Permite al servidor aceptar conexiones
  • accept() - Acepta una conexión de un cliente
  • connect() - Conecta a una dirección remota
  • send() - Envía datos a un socket conectado
  • recv() - Recibe datos de un socket conectado
  • close() - Cierra el socket

En el siguiente paso, crearemos un servidor usando estas funciones.

Creando un Servidor de Socket Simple

Ahora que entendemos los conceptos básicos de los sockets, creemos un servidor simple que escuche las conexiones y reciba mensajes de los clientes.

Cómo Funciona un Servidor de Socket

Un servidor de socket sigue estos pasos generales:

  1. Crea un socket
  2. Lo enlaza a una dirección y un puerto
  3. Escucha las conexiones entrantes
  4. Acepta las conexiones de los clientes
  5. Recibe y procesa datos
  6. Envía una respuesta si es necesario
  7. Cierra la conexión

Implementemos este patrón en Python.

Creando el Servidor

  1. Crea un nuevo archivo Python llamado server.py en el directorio socket_lab:

En el WebIDE, haz clic en el botón "New File" o usa el menú "File" y selecciona "New File", luego nómbralo server.py dentro del directorio socket_lab.

  1. Agrega el siguiente código para crear un servidor básico:
import socket

def start_server():
    ## Server configuration
    host = '127.0.0.1'  ## localhost
    port = 12345        ## arbitrary non-privileged port

    ## Create socket
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    ## Set socket option to reuse address (helps avoid "Address already in use" errors)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    ## Bind socket to address and port
    server_socket.bind((host, port))

    ## Listen for connections (queue up to 5 connection requests)
    server_socket.listen(5)

    print(f"Server started on {host}:{port}")
    print("Waiting for client connection...")

    try:
        ## Accept connection
        client_socket, client_address = server_socket.accept()
        print(f"Connection established with {client_address}")

        ## Receive data from client
        data = client_socket.recv(1024)  ## receive up to 1024 bytes
        print(f"Message received: {data.decode()}")

        ## Send response to client
        response = "Message received by server"
        client_socket.send(response.encode())

        ## Close client connection
        client_socket.close()

    except KeyboardInterrupt:
        print("\nServer shutting down...")
    finally:
        ## Close server socket
        server_socket.close()
        print("Server socket closed")

if __name__ == "__main__":
    start_server()
  1. Guarda el archivo.

Entendiendo el Código del Servidor

Desglosemos los componentes clave de nuestro servidor:

  • Creación del Socket: Creamos un socket TCP usando socket.socket() con AF_INET (IPv4) y SOCK_STREAM (protocolo TCP).

  • Opciones del Socket: Establecemos una opción para reutilizar la dirección, lo que ayuda a prevenir errores de "Address already in use" al reiniciar el servidor rápidamente después del apagado.

  • Enlace (Binding): Enlazamos el socket a la dirección 127.0.0.1 (localhost) y al puerto 12345. Esto le dice al sistema operativo que queremos recibir conexiones en esta ubicación de red específica.

  • Escucha (Listening): La llamada listen(5) le dice al socket que ponga en cola hasta 5 solicitudes de conexión antes de rechazar nuevas conexiones.

  • Aceptación de Conexiones: El método accept() bloquea (espera) hasta que un cliente se conecta, luego devuelve un nuevo objeto socket para comunicarse con ese cliente, junto con la dirección del cliente.

  • Recepción de Datos: Usamos recv(1024) para recibir hasta 1024 bytes de datos del cliente. Los datos vienen como bytes, por lo que usamos decode() para convertirlos en una cadena.

  • Envío de Datos: Enviamos una respuesta al cliente usando el método send(). encode() la cadena para convertirla en bytes antes de enviarla.

  • Cierre: Finalmente, cerramos tanto el socket del cliente como el socket del servidor para liberar recursos.

Probando el Servidor

Ejecutemos nuestro servidor para verlo en acción. Todavía no hará mucho, ya que no hemos creado un cliente, pero podemos verificar que se inicia correctamente:

python3 ~/project/socket_lab/server.py

Deberías ver una salida como esta:

Server started on 127.0.0.1:12345
Waiting for client connection...

El servidor ahora está esperando que un cliente se conecte. Como aún no tenemos un cliente, presiona Ctrl+C para detener el servidor:

^C
Server shutting down...
Server socket closed

En el siguiente paso, crearemos un cliente para conectarnos a nuestro servidor.

Construyendo un Cliente para Conectarse al Servidor

Ahora que tenemos nuestro servidor, necesitamos crear un cliente que pueda conectarse a él y enviar mensajes. Construyamos una aplicación cliente simple.

Cómo Funciona un Cliente de Socket

Un cliente de socket sigue estos pasos generales:

  1. Crea un socket
  2. Se conecta a la dirección y al puerto de un servidor
  3. Envía datos
  4. Recibe una respuesta
  5. Cierra la conexión

Creando el Cliente

  1. Crea un nuevo archivo Python llamado client.py en el directorio socket_lab:

En el WebIDE, haz clic en el botón "New File" o usa el menú "File" y selecciona "New File", luego nómbralo client.py dentro del directorio socket_lab.

  1. Agrega el siguiente código para crear un cliente básico:
import socket

def start_client():
    ## Server information to connect to
    host = '127.0.0.1'  ## localhost - same as server
    port = 12345        ## same port as server

    try:
        ## Create socket
        client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        ## Connect to server
        print(f"Connecting to server at {host}:{port}...")
        client_socket.connect((host, port))
        print("Connected to server")

        ## Send a message
        message = "Hello from the client!"
        print(f"Sending message: {message}")
        client_socket.send(message.encode())

        ## Receive response
        response = client_socket.recv(1024)
        print(f"Response from server: {response.decode()}")

    except ConnectionRefusedError:
        print("Connection failed. Make sure the server is running.")
    except Exception as e:
        print(f"An error occurred: {e}")
    finally:
        ## Close socket
        client_socket.close()
        print("Connection closed")

if __name__ == "__main__":
    start_client()
  1. Guarda el archivo.

Entendiendo el Código del Cliente

Examinemos las partes clave de nuestro código cliente:

  • Creación del Socket: Similar al servidor, creamos un socket TCP usando socket.socket().

  • Conexión: En lugar de enlazar y escuchar, el cliente usa connect() para establecer una conexión con el servidor en el host y puerto especificados.

  • Envío de Datos: Enviamos un mensaje usando el método send(), asegurándonos de codificar la cadena en bytes.

  • Recepción de Datos: Usamos recv(1024) para recibir la respuesta del servidor y la decodificamos de nuevo a una cadena.

  • Manejo de Errores: Incluimos el manejo de errores para detectar problemas comunes como que el servidor no esté disponible (ConnectionRefusedError).

  • Cierre: Cerramos el socket cuando terminamos para liberar recursos.

Probando el Cliente y el Servidor Juntos

Ahora probemos nuestro cliente y servidor juntos. Necesitaremos ejecutarlos en ventanas de terminal separadas.

  1. Primero, inicia el servidor:
python3 ~/project/socket_lab/server.py

Deberías ver:

Server started on 127.0.0.1:12345
Waiting for client connection...
  1. Abre una nueva terminal en WebIDE (haciendo clic en el botón "+" en el panel de la terminal) y ejecuta el cliente:
python3 ~/project/socket_lab/client.py

Deberías ver una salida como esta en la terminal del cliente:

Connecting to server at 127.0.0.1:12345...
Connected to server
Sending message: Hello from the client!
Response from server: Message received by server
Connection closed

Y en la terminal del servidor, deberías ver:

Connection established with ('127.0.0.1', 55234)  ## The port number may differ
Message received: Hello from the client!

Después de que el cliente se desconecte, el servidor se detendrá porque nuestra implementación actual solo maneja una sola conexión. Presiona Ctrl+C en la terminal del servidor para apagarlo si aún se está ejecutando.

Esto demuestra la comunicación exitosa entre un cliente y un servidor usando sockets de Python. El cliente puede enviar un mensaje al servidor, y el servidor puede recibirlo y enviar una respuesta de vuelta.

Construyendo un Servidor Continuo y un Cliente Interactivo

Nuestra implementación actual de servidor-cliente solo maneja un único intercambio de mensajes antes de cerrar. La mayoría de las aplicaciones del mundo real necesitan mantener las conexiones y manejar múltiples mensajes. Mejoremos nuestro código para crear una experiencia más interactiva.

Mejorando el Servidor

Primero, modifiquemos nuestro servidor para aceptar continuamente conexiones y manejar múltiples mensajes de cada cliente.

  1. Abre el archivo server.py en el WebIDE y reemplaza el código con:
import socket

def start_server():
    ## Server configuration
    host = '127.0.0.1'
    port = 12345

    ## Create socket
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    try:
        ## Bind and listen
        server_socket.bind((host, port))
        server_socket.listen(5)

        print(f"Server running on {host}:{port}")
        print("Press Ctrl+C to stop the server")

        while True:  ## Continuous server loop
            print("\nWaiting for a connection...")
            client_socket, client_address = server_socket.accept()
            print(f"Connected to client: {client_address}")

            ## Handle client communication
            handle_client(client_socket)

    except KeyboardInterrupt:
        print("\nServer is shutting down...")
    finally:
        server_socket.close()
        print("Server closed")

def handle_client(client_socket):
    try:
        while True:  ## Keep receiving messages until client disconnects
            ## Receive data
            data = client_socket.recv(1024)

            ## If no data, client has disconnected
            if not data:
                break

            received_message = data.decode()
            print(f"Received: {received_message}")

            ## Process the message (in this case, just echo it back with a prefix)
            response = f"Server received: {received_message}"
            client_socket.send(response.encode())

    except Exception as e:
        print(f"Error handling client: {e}")
    finally:
        ## Close client socket
        client_socket.close()
        print("Client connection closed")

if __name__ == "__main__":
    start_server()
  1. Guarda el archivo.

Mejorando el Cliente

Ahora, creemos un cliente interactivo que permita a los usuarios enviar múltiples mensajes.

  1. Abre el archivo client.py en el WebIDE y reemplaza el código con:
import socket

def start_client():
    ## Server information
    host = '127.0.0.1'
    port = 12345

    try:
        ## Create socket and connect
        client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        print(f"Connecting to server at {host}:{port}...")
        client_socket.connect((host, port))
        print("Connected to server!")

        ## Interactive message sending
        while True:
            ## Get message from user
            message = input("\nEnter message to send (or 'quit' to exit): ")

            ## Check if user wants to quit
            if message.lower() == 'quit':
                print("Closing connection...")
                break

            ## Send message
            client_socket.send(message.encode())

            ## Receive response
            response = client_socket.recv(1024)
            print(f"Response from server: {response.decode()}")

    except ConnectionRefusedError:
        print("Connection failed. Make sure the server is running.")
    except Exception as e:
        print(f"An error occurred: {e}")
    finally:
        ## Close connection
        try:
            client_socket.close()
        except:
            pass
        print("Disconnected from server")

if __name__ == "__main__":
    start_client()
  1. Guarda el archivo.

Entendiendo el Código Mejorado

Mejoras del Servidor:

  • Agregamos un bucle while True externo para aceptar continuamente nuevas conexiones de clientes.
  • Creamos una función separada handle_client para gestionar la comunicación con cada cliente.
  • La función de manejo del cliente tiene su propio bucle para recibir múltiples mensajes del mismo cliente.
  • Verificamos si hay datos vacíos (if not data:), lo que indica que el cliente se ha desconectado.

Mejoras del Cliente:

  • Agregamos un bucle while True para permitir el envío de múltiples mensajes.
  • Solicitamos al usuario que ingrese y lo enviamos al servidor.
  • El usuario puede escribir 'quit' para salir del bucle y cerrar la conexión.
  • Después de enviar cada mensaje, esperamos y mostramos la respuesta del servidor.

Probando las Aplicaciones Mejoradas

Probemos nuestro servidor y cliente mejorados:

  1. Inicia el servidor mejorado en una terminal:
python3 ~/project/socket_lab/server.py

Deberías ver:

Server running on 127.0.0.1:12345
Press Ctrl+C to stop the server

Waiting for a connection...
  1. En una nueva terminal, ejecuta el cliente mejorado:
python3 ~/project/socket_lab/client.py

Deberías ver:

Connecting to server at 127.0.0.1:12345...
Connected to server!

Enter message to send (or 'quit' to exit):
  1. Escribe un mensaje y presiona Enter:
Enter message to send (or 'quit' to exit): Hello, server!
Response from server: Server received: Hello, server!

Enter message to send (or 'quit' to exit):
  1. Intenta enviar algunos mensajes más. En la terminal del servidor, deberías ver que se reciben cada mensaje:
Connected to client: ('127.0.0.1', 59042)
Received: Hello, server!
Received: This is another message
  1. Cuando hayas terminado, escribe 'quit' en el cliente:
Enter message to send (or 'quit' to exit): quit
Closing connection...
Disconnected from server
  1. En la terminal del servidor, deberías ver:
Client connection closed

Waiting for a connection...
  1. El servidor continúa ejecutándose y está listo para aceptar nuevas conexiones. Puedes iniciar otro cliente o presionar Ctrl+C para detener el servidor.

Con estas mejoras, hemos creado un sistema de comunicación cliente-servidor más realista e interactivo utilizando sockets de Python.

Múltiples Clientes y Manejo de Errores

En las aplicaciones del mundo real, un servidor normalmente necesita manejar múltiples clientes simultáneamente y gestionar con elegancia diversas condiciones de error. Mejoremos nuestra implementación teniendo en cuenta estas consideraciones.

Entendiendo el Manejo Concurrente de Clientes

Hay varias formas de manejar múltiples clientes concurrentemente:

  1. Threading (Hilos): Crea un nuevo hilo para cada conexión de cliente
  2. Process-based (Basado en procesos): Genera un nuevo proceso para cada cliente
  3. Asynchronous I/O (E/S asíncrona): Usa E/S no bloqueante con un bucle de eventos

Para este laboratorio, implementaremos un enfoque basado en hilos, que es relativamente simple de entender e implementar.

Mejorando el Servidor para Múltiples Clientes

Modifiquemos nuestro servidor para manejar múltiples clientes usando hilos:

  1. Abre el archivo server.py en el WebIDE y reemplaza el código con:
import socket
import threading

def handle_client(client_socket, client_address):
    """Handle communication with a single client"""
    try:
        print(f"[NEW CONNECTION] {client_address} connected.")

        while True:
            ## Receive client data
            try:
                data = client_socket.recv(1024)
                if not data:
                    break  ## Client disconnected

                message = data.decode()
                print(f"[{client_address}] {message}")

                ## Send response
                response = f"Message '{message}' received successfully"
                client_socket.send(response.encode())

            except ConnectionResetError:
                print(f"[{client_address}] Connection reset by client")
                break

    except Exception as e:
        print(f"[ERROR] {e}")

    finally:
        ## Clean up when client disconnects
        client_socket.close()
        print(f"[DISCONNECTED] {client_address} disconnected")

def start_server():
    """Start the server and listen for connections"""
    ## Server configuration
    host = '127.0.0.1'
    port = 12345

    ## Create socket
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    ## Set socket option to reuse address
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    try:
        ## Bind to host and port
        server_socket.bind((host, port))

        ## Listen for connections
        server_socket.listen(5)
        print(f"[STARTING] Server is listening on {host}:{port}")

        while True:
            ## Accept client connection
            client_socket, client_address = server_socket.accept()

            ## Create a new thread to handle the client
            client_thread = threading.Thread(
                target=handle_client,
                args=(client_socket, client_address)
            )
            client_thread.daemon = True  ## Thread will close when main program exits
            client_thread.start()

            ## Display active connections
            print(f"[ACTIVE CONNECTIONS] {threading.active_count() - 1}")

    except KeyboardInterrupt:
        print("\n[SHUTTING DOWN] Server is shutting down...")
    except Exception as e:
        print(f"[ERROR] {e}")
    finally:
        server_socket.close()
        print("[CLOSED] Server socket closed")

if __name__ == "__main__":
    start_server()
  1. Guarda el archivo.

Mejorando el Cliente con Manejo de Errores

Mejoremos también nuestro cliente con un mejor manejo de errores:

  1. Abre el archivo client.py en el WebIDE y reemplaza el código con:
import socket
import sys
import time

def start_client():
    """Start a client that connects to the server"""
    ## Server information
    host = '127.0.0.1'
    port = 12345

    ## Create socket
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    ## Set a timeout for connection attempts (5 seconds)
    client_socket.settimeout(5)

    try:
        ## Connect to server
        print(f"[CONNECTING] Connecting to server at {host}:{port}...")
        client_socket.connect((host, port))

        ## Reset timeout to none for regular communication
        client_socket.settimeout(None)

        print("[CONNECTED] Connected to server")

        ## Communication loop
        while True:
            ## Get user input
            message = input("\nEnter message (or 'quit' to exit): ")

            if message.lower() == 'quit':
                print("[CLOSING] Closing connection by request...")
                break

            try:
                ## Send message
                client_socket.send(message.encode())

                ## Wait for response
                response = client_socket.recv(1024)
                print(f"[RESPONSE] {response.decode()}")

            except ConnectionResetError:
                print("[ERROR] Connection was reset by the server")
                break
            except ConnectionAbortedError:
                print("[ERROR] Connection was aborted")
                break
            except Exception as e:
                print(f"[ERROR] {e}")
                break

    except socket.timeout:
        print("[TIMEOUT] Connection attempt timed out. Is the server running?")
    except ConnectionRefusedError:
        print("[REFUSED] Connection refused. Make sure the server is running.")
    except KeyboardInterrupt:
        print("\n[INTERRUPT] Client shutting down...")
    except Exception as e:
        print(f"[ERROR] {e}")

    finally:
        ## Close socket
        try:
            client_socket.close()
            print("[DISCONNECTED] Disconnected from server")
        except:
            pass

if __name__ == "__main__":
    start_client()
  1. Guarda el archivo.

Entendiendo el Código Mejorado

Mejoras del Servidor:

  • Hemos agregado el módulo threading para manejar múltiples clientes concurrentemente.
  • Cada conexión de cliente ahora se maneja en un hilo separado.
  • Hemos mejorado el manejo de errores con capturas de excepciones más específicas.
  • Mostramos el número de conexiones de cliente activas.
  • Los hilos se establecen como "daemon" (demonio), lo que significa que se cerrarán automáticamente cuando el programa principal se cierre.

Mejoras del Cliente:

  • Hemos agregado un tiempo de espera de conexión para evitar que se cuelgue si el servidor no está disponible.
  • Hemos mejorado el manejo de errores con capturas de excepciones específicas para diferentes errores de red.
  • Hemos agregado mensajes de estado más descriptivos con un formato claro.

Probando el Servidor Multi-Cliente

Probemos nuestras aplicaciones mejoradas:

  1. Inicia el servidor:
python3 ~/project/socket_lab/server.py

Deberías ver:

[STARTING] Server is listening on 127.0.0.1:12345
  1. En una nueva terminal, inicia un cliente:
python3 ~/project/socket_lab/client.py
  1. Inicia otro cliente en una tercera terminal:
python3 ~/project/socket_lab/client.py
  1. En la terminal del servidor, deberías ver ambas conexiones:
[NEW CONNECTION] ('127.0.0.1', 59124) connected.
[ACTIVE CONNECTIONS] 1
[NEW CONNECTION] ('127.0.0.1', 59126) connected.
[ACTIVE CONNECTIONS] 2
  1. Envía mensajes desde ambos clientes y observa cómo el servidor los recibe:
[('127.0.0.1', 59124)] Hello from client 1
[('127.0.0.1', 59126)] Hello from client 2
  1. Cuando hayas terminado, escribe 'quit' en cada cliente para desconectarte, o presiona Ctrl+C en la terminal del servidor para apagar el servidor.

Manejo de Servidor No en Ejecución

Probemos también qué sucede cuando el servidor no está en ejecución:

  1. Asegúrate de que el servidor esté detenido (presiona Ctrl+C si se está ejecutando)

  2. Intenta ejecutar un cliente:

python3 ~/project/socket_lab/client.py

Deberías ver:

[CONNECTING] Connecting to server at 127.0.0.1:12345...
[REFUSED] Connection refused. Make sure the server is running.
[DISCONNECTED] Disconnected from server

El cliente ahora maneja el error con elegancia, informando al usuario que es posible que el servidor no se esté ejecutando.

Con estas mejoras, hemos creado un sistema cliente-servidor robusto que puede manejar múltiples clientes y diversas condiciones de error. Esta es una base sólida para desarrollar aplicaciones en red más complejas.

Resumen

Felicitaciones por completar este laboratorio sobre programación de sockets en Python. Has aprendido con éxito a:

  1. Crear objetos socket para la comunicación en red
  2. Implementar un servidor TCP que escucha las conexiones
  3. Construir una aplicación cliente que se conecta a un servidor
  4. Enviar y recibir mensajes entre el cliente y el servidor
  5. Mejorar tu servidor para manejar múltiples clientes concurrentemente
  6. Implementar un manejo de errores robusto tanto en el cliente como en el servidor

Estas habilidades forman la base de la programación de red y se pueden aplicar para construir una amplia gama de aplicaciones en red, desde programas de chat simples hasta sistemas distribuidos complejos.

Para continuar tu viaje de aprendizaje, considera explorar:

  • Implementar conexiones de socket seguras con SSL/TLS
  • Construir un protocolo más complejo para intercambiar datos estructurados
  • Crear una GUI para tu aplicación cliente
  • Usar E/S asíncrona para un mayor rendimiento con muchas conexiones concurrentes

Las capacidades de programación de sockets de Python lo convierten en una excelente opción para el desarrollo de aplicaciones de red, ofreciendo un equilibrio entre simplicidad y potencia que pocos otros lenguajes pueden igualar.