How to handle websocket traffic in Python Websocket? - python

I can use websockets in my code and i can easily store it some list. Here is code
import websockets
import asyncio
clients = {}
async def handle_connection(websocket, path):
# save websocket connection in clients dictionary
clients[websocket] = path
try:
# messages from client
async for message in websocket:
for to_client in clients.keys():
dest_username = clients[to_client]
source_username = clients[websocket]
text_data = message
if source_username == dest_username:
await to_client.send(f"{source_username}: {text_data}")
except Exception as e:
print(e)
finally:
# remove websocket connection
clients.pop(websocket)
# websocket server port
PORT = 5678
start_server = websockets.serve(handle_connection, 'localhost', PORT)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
My question is this, is it the correct way to store all websockets in a list ? Because i can not find any example for storing websockets.Some adviced tornado.But are there any best(optimal) solution ? Thank you for your answers

Related

Handle IPV6 adresses in Python asyncio

I'm trying to use asyncio to create a connection to a TCP server in IPV6. This is not working, this function below fails to get the IPv6 server address:
def connection_made(self, transport: transports.BaseTransport) -> None:
peername = transport.get_extra_info('peername')
self.__ip = peername[0]
print('Connection from {}'.format(peername))
# database operation
AckTlvDB.product_online(peername[0], datetime.now())
what is the right way to do it?
my client code :
async def run_client():
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
loop = asyncio.get_event_loop()
on_con_lost = loop.create_future()
transport, protocol = await loop.create_connection(
lambda: AckTlvProtocol(on_con_lost), sock=sock ) # put SERVER6ADDR & SEVERPORT instead of "sock" not working to
try:
await on_con_lost
finally:
transport.close()

server stop receiving msg after 1 msg receive

The idea is to create a server for sending and receiving files for backup, right now the server receives 1 msg from a client in python and another in C++, the problem is, the python client manages to send 1 string and then the server kinda looks, and I have to end the connection, that's for the python client, when I'm trying to send data from the c++ client i got nothing
I'm using Websockets, but my problem seems to be on the try: statement, honestly cant figure it out wheres my problem
sidenote: I'm using quit() to stop my program, but every time I used it I got way too many errors so I had to comment it
Here's my Server.py code
import asyncio
import websockets
import socket
import sqlite3
import sys
def get_ip(): # returns primary private IP only
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# doesn't even have to be reachable
s.connect(('10.255.255.255', 1))
IP = s.getsockname()[0]
except Exception:
IP = '127.0.0.1'
finally:
s.close()
return IP
async def handle_connectio(websocket, path): # recive and handle connection from client, would handle json or file data
while True:
try:
async for name in websocket:
#name = await websocket.recv()
print(f"<<< {name}")
#break
except websockets.exceptions.ConnectionClosed:
print (f"Coneecion terminada")
#quit()
break
else:
print (f"algo paso")
#quit()
break
print ("Iniciando el Server webSocket")
print ("Current Ip: " + get_ip())
servidor = websockets.serve(handle_connectio, get_ip(), 8000)
#loop = asyncio.get_event_loop()
#loop.run_until_complete(servidor)
asyncio.get_event_loop().run_until_complete(servidor)
asyncio.get_event_loop().run_forever()
#async def main(): # main function
# print ("Iniciando Server websocket")
# print("Current Ip: " + get_ip())
# async with websockets.serve(handle_connectio, get_ip(), 8000):
# await asyncio.Future()
#if __name__ == '__main__':
# asyncio.run(main())
edit: I did try to simplify my code and it manages to receive the msg and show when the connection is closed - still the main problem persists.
async def handle_connectio(websocket, path): # recive and handle connection from client, would handle json or file data
try:
while True:
#async for data in websocket:
data = await websocket.recv()
print(f"<<< {data}")
await asyncio.sleep(1)
except websockets.exceptions.ConnectionClosed:
print (f"Coneecion terminada")
edit2: heres my client code, if this donst work i would switch to sockets
import asyncio
import websockets
async def client():
direc = "ws://192.168.1.69:8000"
async with websockets.connect(direc) as web:
while True:
nombre = input("Introduce el mensaje >>> ")
await web.send(nombre)
asyncio.get_event_loop().run_until_complete(client())
From looking at and running the example code at https://websockets.readthedocs.io/en/stable/, it's apparent that your connection handler shouldn't loop forever (while True:) but exit after handling all the messages supplied by the websocket. It will be called again when another message arrives.
Edit:
The original server code works fine. The problem is that the client is using the input() function, which blocks asyncio from running, which prevents websocket protocol from running correctly and blocks messages from sending. A small delay after send (await asyncio.sleep(1)) works, although ideally the input() and the asyncio comm logic would be separated, to avoid an arbitrary delay.
Ok for some odd reason websockets wont work/behave properly so i had to switch to Sockets and now i can send the data back and forth, i would post my client and server code for anyone on the future.
Server.py
import socket
# socket.SOCK_STREAM -> TCP
# socket.SOCK_DGRAM -> UDP
def get_ip(): # returns primary private IP only
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# doesn't even have to be reachable
s.connect(('10.255.255.255', 1))
IP = s.getsockname()[0]
except Exception:
IP = '127.0.0.1'
finally:
s.close()
return IP
def servidor():
print (f"Iniciando el Servidor Sockets")
print (f"Current IP Addres: " + get_ip())
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((get_ip(), 8000))
server.listen(1)
conn, address = server.accept() # Accept the Client connection
while True:
#1024 is the bandwidth bits
try:
msg = conn.recv(1024).decode() # Recive the msg and trasform it from Binary to String
print("<<< " + msg)
except:
print (f"coneccion terminada")
break
if __name__ == "__main__":
servidor()
Client.py
import socket
print ('Iniciando cliente')
conn_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
conn_client.connect( ('192.168.1.68', 8000))
while True:
try:
msg = (f">>> ")
conn_client.sendall(msg.encode())
except:
print (f"Connection Close")
break
#recibido = conn_client.recv(1024)
#print (recibido.decode())
conn_client.close()

TCP client reconnect to server if the server is down (using Asyncio)

I am writing a program using asyncio in python where a Client connects to a server, they exchange some messages and the Server closes the connection.
What I also need to implement is a retry mechanism, where in case the server is down the client will keep trying to reconnect every 5 seconds.
Being new in python and with the asyncio concept in general, I need help to understand how to implement that.
Below is a snippet of my code where I start the connection with the server and where I handle it in case of socket closure on server side.
async def main():
# Get a reference to the event loop as we plan to use
# low-level APIs.
format = "%(asctime)s: %(message)s"
logging.basicConfig(format=format, level=logging.INFO,
datefmt="%H:%M:%S")
executor1 = concurrent.futures.ThreadPoolExecutor(max_workers=2)
future1 = executor1.submit(init_thread)
loop = asyncio.get_running_loop()
on_con_lost = loop.create_future()
message = future1.result()
message = struct.pack(">I", len(message)) + bytes(message, "utf-8")
transport, protocol = await loop.create_connection(
lambda: EchoClientProtocol(message, on_con_lost),
'127.0.0.1', 9000)
# Wait until the protocol signals that the connection
# is lost and close the transport.
try:
await on_con_lost
finally:
transport.close()
asyncio.run(main())

How to structure listen and disseminate with asyncio websockets?

I'm trying to write a server using asyncio/websockets that listens to a single websocket connection on one port, and when it gets a message, it sends that to all of the websockets that are listening to it on a separate port. There could be hundreds of clients on the second port, so I know I need to use the non-blocking await websocket.send(msg). But I can't figure out how to structure this listen/disseminate paradigm in terms of the event loops.
Here's my first attempt:
import asyncio
import websockets
import time
LISTEN_PORT = 8080
SPEAK_PORT = 8081
audience = []
async def add_audience_member(websocket, path):
global audience
print('New audience member!')
audience.append(websocket)
async def add_source(websocket, path):
global audience
while True:
msg = await websocket.recv()
for ws in audience:
await ws.send(msg + ' ' + str(time.time()))
loop = asyncio.get_event_loop()
loop.run_until_complete(websockets.serve(add_audience_member, HOST, SPEAK_PORT))
loop.run_until_complete(websockets.serve(add_source, HOST, LISTEN_PORT))
loop.run_forever()
Then I have a client running:
from websocket import create_connection
ws = create_connection('ws://{}:{}'.format(HOST, 8081))
while True:
data = ws.recv(); print data
The problem is that add_audience_member closes the connection as soon as it adds the new websocket to the audience list, so I get the error:
websocket._exceptions.WebSocketConnectionClosedException: Connection is already closed.

How to create TCP proxy server with asyncio?

I found these example with TCP client and server on asyncio: tcp server example. But how to connect them to get TCP proxy server which will be receive data and send it to other adress?
You can combine both the TCP client and server examples from the user documentation.
You then need to connect the streams together using this kind of helper:
async def pipe(reader, writer):
try:
while not reader.at_eof():
writer.write(await reader.read(2048))
finally:
writer.close()
Here's a possible client handler:
async def handle_client(local_reader, local_writer):
try:
remote_reader, remote_writer = await asyncio.open_connection(
'127.0.0.1', 8889)
pipe1 = pipe(local_reader, remote_writer)
pipe2 = pipe(remote_reader, local_writer)
await asyncio.gather(pipe1, pipe2)
finally:
local_writer.close()
And the server code:
# Create the server
loop = asyncio.get_event_loop()
coro = asyncio.start_server(handle_client, '127.0.0.1', 8888)
server = loop.run_until_complete(coro)
# Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
# Close the server
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()

Categories