Simple programa Cliente/Servidor (socket) en python

En la entrada de hoy veremos un simple ejemplo de un programa cliente/servidor utilizando el módulo socket en python. El módulo socket (canal de comunicación) es utilizado para comunicar un programa cliente con un programa servidor en una red (también se puede utilizar en el mismo equipo).

Los socket se pueden configurar para que actúen como un servidor y así poder escuchar los mensajes entrantes, o conectarse a otras aplicaciones como clientes. Luego de que ambos extremos de un socket TCP/IP están conectados, la comunicación es bidireccional.

Estas primeros ejemplos que explico, fueron creados en "localhost" en un PC con sistema Linux (Ubuntu).

Cliente - Servidor

Cliente - Servidor

Creando un programa Servidor

Este sencillo código de ejemplo (Servidor.py), recibe mensajes entrantes y los ecos de vuelta al remitente. Esto se hace creando un socket TCP/IP:

#!/usr/bin/python
# -*- coding: utf-8 -*-

# Programa Servidor
# www.pythondiario.com

import socket
import sys

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

Luego el método bind() es utilizado para asociar un socket a una dirección de servidor. En este caso, la dirección es un localhost (dirección actual) y el número de puerto es 10000.

# Enlace de socket y puerto
server_address = ('localhost', 10000)
print >>sys.stderr, 'empezando a levantar %s puerto %s' % server_address
sock.bind(server_address)

El método accept() acepta una conexión entrante (un cliente) y el método listen() pone al socket en modo servidor.

# Escuchando conexiones entrantes
sock.listen(1)

while True:
    # Esperando conexion
    print >>sys.stderr, 'Esperando para conectarse'
    connection, client_address = sock.accept()

El método accept() nos devuelve una conexión abierta entre el servidor y el cliente, junto con la dirección del cliente. Los datos de la conexión se leen con el método recv() y se transmiten con el método sendall().

while True:
    # Esperando conexion
    print >>sys.stderr, 'Esperando para conectarse'
    connection, client_address = sock.accept()

    try:
        print >>sys.stderr, 'concexion desde', client_address

        # Recibe los datos en trozos y reetransmite
        while True:
            data = connection.recv(19)
            print >>sys.stderr, 'recibido "%s"' % data
            if data:
                print >>sys.stderr, 'enviando mensaje de vuelta al cliente'
                connection.sendall(data)
            else:
                print >>sys.stderr, 'no hay mas datos', client_address
                break
            
    finally:
        # Cerrando conexion
        connection.close()

Cuando se termina la comunicación con un cliente, la conexión debe ser cerrada con el método close(). Nuestro ejemplo utiliza try:finally para asegurar que la conexión sea cerrada igual en caso de un error.

Creando un programa Cliente

El código para el programa cliente (Cliente.py) utiliza el socket diferente a como lo hace el Servidor. En lugar de unirse a un puerto para escuchar conexiones, utiliza el método connect() para fijar una conexión remota.

#!/usr/bin/python
# -*- coding: utf-8 -*-

# Programa Cliente
# www.pythondiario.com

import socket
import sys

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

# Conecta el socket en el puerto cuando el servidor esté escuchando
server_address = ('localhost', 10000)
print >>sys.stderr, 'conectando a %s puerto %s' % server_address
sock.connect(server_address)

Después que la conexión esté establecida, la información puede ser enviada con el método sendall() y recibida con el método recv(), igual que el servidor.

try:
    
    # Enviando datos
    message = 'Este es el mensaje.  Se repitio.'
    print >>sys.stderr, 'enviando "%s"' % message
    sock.sendall(message)

    # Buscando respuesta
    amount_received = 0
    amount_expected = len(message)
    
    while amount_received < amount_expected:
        data = sock.recv(19)
        amount_received += len(data)
        print >>sys.stderr, 'recibiendo "%s"' % data

finally:
    print >>sys.stderr, 'cerrando socket'
    sock.close()

Finalmente, cuando el mensaje es enviado, y la copia recibida, la conexión se cierra para dejar libre el puerto.


Diagrama de nuestro programa Cliente - Servidor

Diagrama Cliente/Servidor

Diagrama Cliente/Servidor



Corriendo nuestros programas Servidor.py y Cliente.py



Ejecutaremos los programas en dos ventanas diferentes para que puedan comunicarse entre si. Esta es la salida impresa del Servidor:

Salida impresa del Servidor
Salida impresa del Servidor

Salida impresa del programa Cliente:

Salida impresa del Cliente
Salida impresa del Cliente



Prueba de comunicación con dos equipos diferentes

Estuve realizando algunas pruebas con 2 computadoras virtuales diferentes (una con Windows XP y otra con Windows 7).

El programa servidor lo corrí en la PC virtual con Windows XP y lo único que cambié en el código de Servidor.py fue el "localhost" por "" (se deja vacío).

# Enlace de socket y puerto
server_address = ('', 10000)
print >>sys.stderr, 'empezando a levantar %s puerto %s' % server_address
sock.bind(server_address)

El programa Cliente.py lo corrí en la PC virtual con Windows 7 y lo único que le modifique fue el "localhost" por la dirección IP del PC con Windows XP (Servidor):

# Conecta el socket en el puerto cuando el servidor esté escuchando
server_address = ('xxx.xxx.xxx.xxx', 10000)
print >>sys.stderr, 'conectando a %s puerto %s' % server_address
sock.connect(server_address)

Luego hice las pruebas de forma inversa. El PC con Windows 7 actuó como Servidor y el PC con Windows XP funcionó como Cliente.

Las pruebas en ambos casos funcionaron correctamente.

Espero esta entrada sea de ayuda para iniciarse con los socket en python. Cualquier duda o sugerencia pueden dejarlas al final de la entrada.

Fuente del material: http://pymotw.com/2/socket/tcp.html

  1. Unknown dice:

    ¿Hola sabes que pudo haber pasado aquí? , supongo que tengo que desactivar el firewall de windows o el antivirus, me salio este error:

    Traceback (most recent call last):
    File "C:Python27cliente_socket", line 30, in
    data = sock.recv(19)
    error: [Errno 10053] Se ha anulado una conexión establecida por el software en su equipo host.

    saludos

    1. PythonDiario dice:

      A mi me ha pasado mas que nada tener que desactivar el firewall, prueba eso y despues me cuentas. Saludos

    2. Unknown dice:

      Como debo proceder ? sera que saben algo al respecto?

    3. Anónimo dice:

      Mascamonda

  2. Unknown dice:

    Buenas mucho gusto.

    En mi caso necesito conectarme desde una pc con ubuntu a una base de datos alojada en windows, usando python . y la bd es SQL Anywhere

    1. Anónimo dice:

      Has probado conectarte con MySQL??

  3. Tomas dice:

    ¿Esto funciona con diferentes computadora?

  4. Unknown dice:

    esto funciona con dos raspberry conectados mediante OTG (USB)?

  5. Unknown dice:

    gracias amigo por este aporte lo voy probar mi proyecto es crear un x cyber para controlar todos lo pc de un cyber

    1. PythonDiario dice:

      Excelente, me alegra mucho!!! Saludos y gracias por visitar el blog

  6. Anónimo dice:

    Muchas gracias por el aporte, estuve buscando un ejemplo entendible, funciona en una sola máquina y también si lo pasas a otras maquinas dentro de la misma red, muchas gracias saludos

  7. Unknown dice:

    Excelente aporte gracias! es fácil de comprender y sirve para entender el flujo de datos :).

  8. WebMaster dice:

    Tengo un problema. Al enviar el mensaje UDP como cliente, el puerto del servidor sale bien pero el propio del cliente cambia en cada mensaje enviado por lo que nunca recibe contestacion por parte del servidor. ¿Que estoy olvidando?
    Gracias de antemano..... Un blog muy currado.

  9. Unknown dice:

    Una pregunta, para realizar la simulación entre dos máquinas diferentes no importa especificar el puerto de conexión en caso de las computadoras estén conectadas por medio de un cable USB?

  10. Revsky dice:

    Si q1uisiera ocupar tu ejemplo para poder intercambiar archivos entre uno y otro es decir:

    Computadoras en red (Envian datos a servidor)
    Servidor (Envia datos a computadoras en red) es decir:

    Que el cliente mande un mensaje al servidor; por ejemplo, mandame una imagen, y el servidor le responda enviando una imagen.

    o que desde el servidor pueda enviar un archivo a los pc en red sin necesidad de una peticion por parte de los usuarios

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir
White Monkey