fbpixel
Etiquetas: ,

Vamos a ver cómo configurar la comunicación entre un servidor y un cliente utilizando el protocolo Websockets en Python. WebSockets es un protocolo de comunicación web simple y robusto para la comunicación en tiempo real.

Instalación de la biblioteca Websockets

Para utilizar WebSockets con Python, instalamos el paquete necesario…

python3 -m pip install websockets

También utilizamos la biblioteca asyncio, que permite la programación asíncrona para el desarrollo de servidores de alto rendimiento.

Recuperar la dirección IP del servidor

Como en todas las comunicaciones por Internet, para establecer una conexión entre el cliente y el servidor es necesario conocer la dirección IP del servidor.

Para obtener la dirección IP de la máquina servidor puede utilizar los comandos ipconfig (Windows) o ifconfig/ ip addr (Linux) (aquí: 192.168.1.59).

window-ipconfig-ip-subnet-gateway Comunicación entre servidor y cliente WebSockets con Python

También puede utilizar el paquete socket en el script Python

def getIpAddress():
	import socket
	s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	s.connect(("8.8.8.8", 80))
	ipaddress = s.getsockname()[0]
	s.close()
	return ipaddress

ipaddress = getIpAddress()

Anota la dirección, la utilizarás en el código de cliente.

Código Python para el servidor WebSocket

Para lanzar el servidor, definimos una función main que abrirá el servidor en el puerto 8765 y lo ejecutará en un bucle. También llamamos a la función de devolución de llamada echo(), que se encargará de la recepción del mensaje. En este ejemplo, devolvemos el mensaje tal cual al cliente.

#!/usr/bin/env python
# python3 -m pip install websockets

import asyncio
from websockets.server import serve

def getIpAddress():
	import socket
	s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	s.connect(("8.8.8.8", 80))
	ipaddress = s.getsockname()[0]
	s.close()
	return ipaddress

ipaddress = getIpAddress()
port = 8765

async def echo(websocket):
	async for message in websocket:
		print("received from {}:{} : ".format(websocket.remote_address[0],websocket.remote_address[1]) + message)
		await websocket.send(message)

async def main():
	print("Server is activated on ws://{}:{}".format(ipaddress,port))
	#async with serve(echo, "localhost", 8765):
	async with serve(echo, "0.0.0.0", port):
		await asyncio.Future()  # run forever

asyncio.run(main())

Nota: para que el servidor sea visible en la red fuera del ordenador, debe especificar la dirección «0.0.0.0» en lugar de «localhost».

Código Python para el cliente WebSocket

En el código del cliente, nos conectamos al servidor especificando la dirección IP y el puerto. A continuación, enviamos un mensaje. Por último, esperamos a que aparezca el mensaje de respuesta.

#!/usr/bin/env python
# python3 -m pip install websockets

import asyncio
from websockets.sync.client import connect

def hello():
    #with connect("ws://localhost:8765") as websocket:
    with connect("ws://192.168.1.52:8765") as websocket:
    
        websocket.send("Hello world!")
        message = websocket.recv()
        print(f"Received from server : {message}")

hello()

Resultados

En un terminal, ejecute primero el script del servidor: python websocket_server.py

python-websockets-server Comunicación entre servidor y cliente WebSockets con Python

En un segundo terminal, ejecute el script de clientee; python websocket_client.py

python-websockets-client Comunicación entre servidor y cliente WebSockets con Python

Intercambio de mensajes JSON a través de WebSocket

JSON (JavaScript Object Notation) es un formato de intercambio de datos muy popular para la comunicación web. Para intercambiar datos JSON entre servidor y cliente utilizamos la librería json preinstalada

En el script de clientee, enviaremos una petición en formato JSON. El servidor recibirá esta petición, comprobará los valores y enviará una respuesta con el resultado de la validación.

Las funciones que necesitas conocer para manejar el formato JSON son:

  • json.loads() para pasar de String a dict
  • json.dumps() para pasar de un dict a un String

Otros formatos de Python pueden convertirse en su equivalente JSON

PythonJSON
dictobject
list, tuplearray
strstring
int, float, intnumber
Truetrue
Falsefalse
Nonenull

script de cliente

#!/usr/bin/env python
# python3 -m pip install websockets
import json
import asyncio
from websockets.sync.client import connect

jsondata = {"type": "setParam", "param1": 30, "param2": 2.3}
jsonwrong = {"type": "setParam", "param1": 30, "param2": -2.3}
jsonunkn = {"type": "setData", "param1": 30, "param2": 2.3}

def hello():
	with connect("ws://192.168.1.52:8765") as websocket:
		websocket.send("Hello world!")
		message = websocket.recv()
		print(f"Received from server : {message}")

		websocket.send(json.dumps(jsondata))
		message = websocket.recv()
		print(f"Received from server : {message}")

		websocket.send(json.dumps(jsonwrong))
		message = websocket.recv()
		print(f"Received from server : {message}")
				
		websocket.send(json.dumps(jsonunkn))
		message = websocket.recv()
		print(f"Received from server : {message}")

hello()

script de servidor

#!/usr/bin/env python
# python3 -m pip install websockets

import json
import asyncio
from websockets.server import serve

def getIpAddress():
	import socket
	s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	s.connect(("8.8.8.8", 80))
	ipaddress = s.getsockname()[0]
	s.close()
	return ipaddress

ipaddress = getIpAddress()
port = 8765

async def echo(websocket):
	async for message in websocket:
		print("received from {}:{} : ".format(websocket.remote_address[0],websocket.remote_address[1]) + message)
		
		if('{' not in message):
			await websocket.send(message)
		else:
			request = json.loads(message)
			answer = {}
			if(request['type'] == 'setParam'):
				answer['type'] = request['type']
				if(request['param1']<100 and request['param2']>1.2):
					answer['valid'] = True
					for key, val in request.items():
						print("\t"+key+": ", val)
				else:
					answer['valid'] = False
			else:
				answer['type'] = 'unknown'
				answer['valid'] = False
				
			await websocket.send(json.dumps(answer))

async def main():
	print("Server is activated on ws://{}:{}".format(ipaddress,port))
	#async with serve(echo, "localhost", 8765):
	async with serve(echo, "0.0.0.0", port):
		await asyncio.Future()  # run forever

asyncio.run(main())

Resultados

python-websockets-server-json Comunicación entre servidor y cliente WebSockets con Python
python-websockets-client-json Comunicación entre servidor y cliente WebSockets con Python

Fuentes