fbpixel
Etiquetas: ,

Vamos ver como configurar a comunicação entre um servidor e um cliente usando o protocolo Websockets em Python. O WebSockets é um protocolo de comunicação web simples e robusto para comunicação em tempo real.

Instalando a biblioteca Websockets

Para utilizar WebSockets com Python, instalamos o pacote necessário…

python3 -m pip install websockets

Também usamos a biblioteca asyncio, que permite a programação assíncrona para o desenvolvimento de servidores de alto desempenho.

Recuperar o endereço IP do servidor

Como em todas as comunicações na Internet, para estabelecer uma ligação entre o cliente e o servidor, é necessário conhecer o endereço IP do servidor.

Para obter o endereço IP da máquina do servidor, pode utilizar os comandos ipconfig (Windows) ou ifconfig/ ip addr (Linux) (aqui: 192.168.1.59).

window-ipconfig-ip-subnet-gateway Comunicação entre servidor e cliente WebSockets com Python

Também pode utilizar o pacote socket no 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()

Tome nota do endereço, que será utilizado no código de cliente.

Código Python para o servidor WebSocket

Para lançar o servidor, definimos uma função principal que abrirá o servidor na porta 8765 e o executará em um loop. Também chamamos a função de retorno de chamada echo(), que tratará da receção da mensagem. Neste exemplo, devolvemos a mensagem tal como está para o 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 o servidor seja visível na rede fora do computador, é necessário especificar o endereço “0.0.0.0” em vez de “localhost”.

Código Python para o cliente WebSocket

No código do cliente, ligamo-nos ao servidor especificando o endereço IP e a porta. De seguida, enviamos uma mensagem. Por fim, aguardamos que a mensagem de resposta seja apresentada.

#!/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

Em um terminal, primeiro execute o script do servidor: python websocket_server.py

python-websockets-server Comunicação entre servidor e cliente WebSockets com Python

Num segundo terminal, execute o script do cliente; python websocket_client.py

python-websockets-client Comunicação entre servidor e cliente WebSockets com Python

Troca de mensagens JSON via WebSocket

O JSON (JavaScript Object Notation) é um formato de intercâmbio de dados muito popular para a comunicação na Web. Para trocar dados JSON entre o servidor e o cliente, usamos a biblioteca json pré-instalada

No script do cliente, enviaremos um pedido em formato JSON. O servidor recebe este pedido, verifica os valores e envia uma resposta com o resultado da validação.

As funções que precisa de conhecer para gerir o formato JSON são:

  • json.loads() para mudar de uma String para um dict
  • json.dumps() para passar de um dict para uma String

Outros formatos Python podem ser convertidos no seu equivalente JSON

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

guião do 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 do 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 Comunicação entre servidor e cliente WebSockets com Python
python-websockets-client-json Comunicação entre servidor e cliente WebSockets com Python

Fontes