fbpixel
Étiquettes : ,

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)

window-ipconfig-ip-subnet-gateway Communication entre serveur et client WebSockets avec Python

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

python-websockets-server Communication entre serveur et client WebSockets avec Python

Dans un second terminal, lancez ensuite le script client ; python websocket_client.py

python-websockets-client Communication entre serveur et client WebSockets avec Python

É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

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

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

python-websockets-server-json Communication entre serveur et client WebSockets avec Python
python-websockets-client-json Communication entre serveur et client WebSockets avec Python

Sources