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).
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
En un segundo terminal, ejecute el script de clientee; python websocket_client.py
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
Python | JSON |
---|---|
dict | object |
list , tuple | array |
str | string |
int , float , int | number |
True | true |
False | false |
None | null |
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