Saltar al contenido principal

📧 Comunicación entre procesos: Cliente y Servidor

🎯 Objetivo de aprendizaje​

  • Comprender los mecanismos de comunicación entre procesos (IPC) utilizando sockets.
  • Crear un servidor y un cliente en Python.
  • Identificar el rol del sistema operativo en la gestión de las conexiones de red.

📜 Enunciado​

En este ejercicio, usted va a crear una aplicación simple de comunicación entre un cliente y un servidor utilizando sockets en Python.

🔧 Paso 1 – Crear un servidor simple​

Un servidor:

  • Abre una "puerta" (llamada puerto) en su computadora.
  • Espera a que un cliente se conecte.
  • Recibe los mensajes del cliente.

Código del servidor​

Cree un archivo llamado serveur.py y copie el siguiente código:

import socket

# Crée un socket TCP
serveur = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# L'adresse IP et le port à utiliser
hote = 'localhost'
port = 12345

# Lier le socket à l'adresse
serveur.bind((hote, port))

# Écoute jusqu'à 1 connexion
serveur.listen(1)
print("[Serveur] En attente de connexion...")

# Accepter la connexion
connexion, adresse = serveur.accept()
print(f"[Serveur] Connexion de {adresse}")

# Réception des messages
while True:
message = connexion.recv(1024).decode()
if message.lower() == "exit":
print("[Serveur] Fin de la communication.")
break
print(f"[Client] {message}")

# Fermer les connexions
connexion.close()
serveur.close()

Prueba​

Este programa no hace nada hasta que un cliente se conecta. Inicie el servidor con el comando:

python serveur.py

y conéctese con su navegador web yendo a http://localhost:12345.

tip

Puede detener el servidor presionando Ctrl+C en la terminal.

💬 Paso 2 – Crear un cliente​

Un cliente:

  • Se conecta a un servidor (aquí mediante localhost y el puerto).
  • Envía los mensajes que usted escribe en la consola.

2.1 Código del cliente​

Cree un archivo client.py:

import socket

# Crée un socket TCP
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Se connecter au serveur
client.connect(('localhost', 12345))
print("[Client] Connecté au serveur. Tapez vos messages :")

# Lire et envoyer les messages
while True:
message = input(">>> ")
client.sendall(message.encode())
if message.lower() == "exit":
break

# Fermer la connexion
client.close()

2.2 Prueba​

  1. En una terminal: ejecute python serveur.py
  2. En otra terminal: ejecute python client.py
  3. Intercambie algunos mensajes.
  4. Escriba exit para detener.

🔁 Paso 3 – Comunicación en ambos sentidos​

Actualmente, solo el cliente habla y el servidor escucha. Ahora vamos a permitir que el servidor responda.

3.1 Usar threading para escuchar y escribir al mismo tiempo​

Cree un archivo llamado serveur2.py y copie el siguiente código:

import socket
import threading

def recevoir(connexion):
while True:
try:
message = connexion.recv(1024).decode()
if not message or message.lower() == "exit":
print("[Client] a quitté la conversation.")
print("[Serveur >>>] ", end="", flush=True)
break
print(f"[Client] {message}")
print("[Serveur >>>] ", end="", flush=True)
except: # noqa: E722
break

def envoyer(connexion):
while True:
try:
message = input("[Serveur >>>] ")
connexion.sendall(message.encode())
if message.lower() == "exit":
break
except: # noqa: E722
break

# Création du serveur
serveur = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serveur.bind(('localhost', 12345))
serveur.listen(1)

print("[Serveur] En attente de connexion...")
connexion, adresse = serveur.accept()
print(f"[Serveur] Connecté à {adresse}")

# Démarrage des threads
thread1 = threading.Thread(target=recevoir, args=(connexion,))
thread2 = threading.Thread(target=envoyer, args=(connexion,))
thread1.start()
thread2.start()

thread1.join()
thread2.join()
connexion.close()
serveur.close()

Cree un archivo llamado client2.py y copie el siguiente código:

import socket
import threading

def recevoir(sock):
while True:
message = sock.recv(1024).decode()
if message.lower() == "exit":
print("[Serveur] a quitté la conversation.")
print("[Client >>>] ", end="", flush=True)
break
print(f"[Serveur] {message}")
print("[Client >>>] ", end="", flush=True)

def envoyer(sock):
while True:
message = input("[Client >>>] ")
sock.sendall(message.encode())
if message.lower() == "exit":
break

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('localhost', 12345))
print("[Client] Connecté au serveur.")

# Démarrage des threads
thread1 = threading.Thread(target=recevoir, args=(client,))
thread2 = threading.Thread(target=envoyer, args=(client,))
thread1.start()
thread2.start()

thread1.join()
thread2.join()
client.close()

✅ Resultado esperado​

  1. Ejecute serveur2.py en una terminal.
  2. Ejecute client2.py en otra.
  3. Intente intercambiar mensajes en ambos sentidos.
  4. Cierre correctamente con exit.

Ejemplo de comunicación entre cliente y servidor

📝 Paso 4 – El sistema operativo​

El sistema operativo juega un papel crucial en la gestión de las conexiones de red. Administra los recursos, los puertos y asegura que los datos se envíen y reciban correctamente. Lo mismo ocurre con los threads, que permiten ejecutar varias tareas en paralelo, como escuchar y enviar mensajes al mismo tiempo.

Responda a las siguientes preguntas:

  • En el código del servidor y del cliente, ¿en qué momento está implicado el sistema operativo?
  • ¿Los threads son gestionados por el sistema operativo (OS thread) o por Python (application thread)?
  • ¿Por qué es importante cerrar las conexiones correctamente?
  • ¿Qué sucede si intenta iniciar el servidor varias veces en el mismo puerto sin cerrarlo?
  • ¿Qué sucede si intenta iniciar el cliente antes que el servidor?