# compatibile Windows 11 # compatibile Ubuntu 24.10 # compatibile python 3.12.7 import asyncio import websockets import json import sys import threading connected_clients = {} # Dizionario: websocket -> porta del client main_task = None # Global variable to hold the main task stop_future = None # Global variable for the stop future loop = None # Global variable to hold the event loop async def echo(websocket): """Gestisce una singola connessione WebSocket.""" client_port = websocket.remote_address[1] connected_clients[websocket] = client_port print(f"Nuova connessione da: {websocket.remote_address} con porta: {client_port}") try: async for message in websocket: try: print(f"Ricevuto: {message} da {websocket.remote_address} con porta: {client_port}") message_to_forward = { "sender_port": client_port, "message": message } message_json = json.dumps(message_to_forward) for recipient, recipient_port in connected_clients.items(): if recipient != websocket: try: await recipient.send(message_json) print(f"Inoltrato messaggio da {client_port} a {recipient_port}") except websockets.ConnectionClosed: print(f"Impossibile inoltrare a {recipient_port} (connessione chiusa)") except Exception as e: print(f"Errore durante l'elaborazione del messaggio da {websocket.remote_address}: {e}") break except websockets.ConnectionClosedError: print(f"Connessione chiusa inaspettatamente da {websocket.remote_address} con porta: {client_port}") except websockets.ConnectionClosedOK: print(f"Connessione chiusa normalmente da {websocket.remote_address} con porta: {client_port}") except Exception as e: print(f"Errore durante la gestione della connessione da {websocket.remote_address} con porta: {client_port}: {e}") finally: if websocket in connected_clients: del connected_clients[websocket] print(f"Connessione con {websocket.remote_address} (porta: {client_port}) terminata.") async def server_main(stop_future): """Avvia il server WebSocket.""" async with websockets.serve(echo, "0.0.0.0", 8765, ping_interval=None): print("Server WebSocket in ascolto su ws://0.0.0.0:8765") await stop_future def input_thread(stop_future, loop): """Legge l'input da console in un thread separato.""" async def set_stop_future(): """Coroutine to set the future's result.""" stop_future.set_result(None) while True: line = sys.stdin.readline().strip() if line == "exit": print("\nServer: Ricevuto comando 'exit', chiusura del server...") asyncio.run_coroutine_threadsafe(set_stop_future(), loop) break async def main(): """Funzione principale per avviare il server e gestire l'input.""" global main_task, stop_future, loop loop = asyncio.get_running_loop() stop_future = asyncio.Future() main_task = asyncio.create_task(server_main(stop_future)) print(f"Main task created: {main_task}") input_thread_instance = threading.Thread(target=input_thread, args=(stop_future, loop), daemon=True) input_thread_instance.start() try: await main_task except asyncio.CancelledError: print("Server: Server task cancelled, shutting down...") except Exception as e: # Catch other potential errors print(f"Server: Error in main: {e}") finally: print("Server: Server shutdown completed.") if __name__ == "__main__": asyncio.run(main())