Nous allons voir comment mettre en place une communication entre un serveur et un client en utilisant le protocole Websockets sous Python. WebSockets est un protocole de communication web simple et robuste permettant la communication en temps réel.
Installation de la librairie Websockets
Pour utiliser les WebSockets avec Python, nous installons le paquet nécessaire..
python3 -m pip install websockets
Nous utilisons aussi la librairie asyncio qui permet de faire de la programmation asynchrone pour le développement de serveur performant
Récupérer l’adresse IP du serveur
Comme dans toute communication internet, pour établir une connexion entre le client et le serveur, il faut connaître l’addresse IP du serveur.
Pour récupérer l’adresse IP de la machine serveur vous pouvez utiliser les commandes ipconfig (Windows) ou ifconfig/ ip addr (Linux) (ici: 192.168.1.59)
Il est aussi possible d’utiliser le paquet socket dans le 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()
Notez l’adresse, vous l’utiliserez dans le code client.
Code Python pour le serveur WebSocket
Pour lancer le serveur, nous définissons une fonction main qui va ouvrir le serveur sur le port 8765 et le faire tourner en boucle. Nous appelons aussi la fonction callback echo() qui va gérer la réception de message. Dans cet exemple, nous renvoyons le message tel quel au client.
#!/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())
N.B.: pour que le serveur soit visible sur le réseau extérieur à l’ordinateur vous devez spécifier l’adresse « 0.0.0.0 » à la place de « localhost »
Code Python pour le client WebSocket
Dans le code client, nous nous connectons au serveur en spécifiant l’adresse IP et le port. Puis, nous envoyons un message. Enfin on attend le message de réponse pour l’afficher.
#!/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()
Résultat
Dans un terminal, lancez d’abord le script serveur: python websocket_server.py
Dans un second terminal, lancez ensuite le script client ; python websocket_client.py
Échange de message JSON via WebSocket
Le format JSON(JavaScript Object Notation) est un format d’échange de donnée très populaire dans la communication web. NousPour échanger des données JSON entre serveur et client nous utilisons la libraire pré-installée json
Dans le script client, nous allons envoyer une requête au format JSON. Le serveur va recevoir cette requête vérifier les valeurs et envoyer une réponse avec le résultat de la validation.
Les fonctions à connaitre pour gérer le format JSON sont:
- json.loads() pour passer d’un String à un dict
- json.dumps() pour passer d’un dict à un String
D’autre format Python peuvent être converti en leur équivalent JSON
Python | JSON |
---|---|
dict | object |
list , tuple | array |
str | string |
int , float , int | number |
True | true |
False | false |
None | null |
script client
#!/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 serveur
#!/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())
Résultat