# compatibile Windows 11 # compatibile Ubuntu 24.10 # compatibile python 3.12.7 import asyncio import signal from time import sleep import websockets import json import functools # Import functools websocket = None # Variabile globale per tenere traccia del websocket receive_task = None # Variabile globale per la task di ricezione main_task = None # Variabile globale to hold the main task - ADDED BACK async def receive_messages(ws): """Funzione asincrona dedicata alla ricezione e gestione dei messaggi dal server.""" try: while True: try: response = await ws.recv() # Prova a decodificare la risposta come JSON try: data = json.loads(response) print(f"Data ricevuta (task receive): {data}") # Stampa l'identificativo del mittente e il messaggio # print(f"Ricevuto da porta (task receive): {data['sender_port']}: {data['message']}") # PARSA IL MESSAGGIO JSON STRINGA DENTRO DATA['message'] try: message_content = json.loads(data['message']) # print(f"Message content parsed (task receive): {message_content}") if "action" in message_content: if message_content["action"] == "saluta": nome = message_content.get("nome", "Sconosciuto") # print(f"Nome (task receive): {nome}") elif message_content["action"] == "somma": a = message_content.get("a", 0) b = message_content.get("b", 0) risultato = a + b # print(f"Somma (task receive): {risultato}") else: # print("Nessuna azione specificata (task receive).") pass else: # print("Nessuna azione trovata nel messaggio (task receive).") pass except json.JSONDecodeError: # print("Il contenuto del messaggio non è un JSON valido (task receive).") pass except (json.JSONDecodeError, KeyError): print(f"Ricevuto (task receive): {response}") except websockets.ConnectionClosed: print("Connessione chiusa dal server (task receive).") break except Exception as e: print(f"Errore durante la ricezione (task receive): {e}") break finally: print("Task di ricezione terminato.") async def connect_and_send(): """Si connette al server WebSocket, invia messaggi e avvia la ricezione in background.""" global websocket, receive_task, main_task # Usa la variabile globale, including main_task # uri = "ws://localhost:8765" # per il server in python uri = "ws://localhost:8765/Echo" # per il server in C# try: async with websockets.connect(uri, ping_interval=None) as ws: websocket = ws # Assegna il websocket connesso alla variabile globale print(f"Connesso al server WebSocket: {uri}") # Avvia la task di ricezione in background receive_task = asyncio.create_task(receive_messages(websocket)) # Task creation is NOW INSIDE connect_and_send print(f"Task di ricezione creata: {receive_task}") # DEBUG n = 0 # Inizializza n qui while True: try: # Invia un semplice messaggio di testo print(f" SEND client n.{n}") await websocket.send(f"Ciao dal client n.{n}") # Usa f-string qui n += 1 # Incrementa n dopo l'invio # Invia un messaggio JSON messaggio_json = {"action": "saluta", "nome": "Alice"} await websocket.send(json.dumps(messaggio_json)) # Invia un altro messaggio JSON (richiesta di somma) messaggio_json = {"action": "somma", "a": 5, "b": 3} await websocket.send(json.dumps(messaggio_json)) # Non attendere la risposta qui, la ricezione è gestita dalla task receive_messages # sleep(5) # Mantieni un intervallo tra gli invii (opzionale) await asyncio.sleep(5) # Usa asyncio.sleep per non bloccare il loop eventi except websockets.ConnectionClosed: print("Connessione chiusa dal server (task send).") break except Exception as e: print(f"Errore durante l'invio (task send): {e}") break except asyncio.CancelledError: print("Connessione interrotta e chiusa correttamente a seguito di CancelledError.") # DEBUG except Exception as e: print(f"Errore in connect_and_send: {e}") finally: print("Finally block in connect_and_send started.") # DEBUG if websocket: # Controlla solo se websocket esiste (non è None) - MODIFICA QUI await websocket.close() print("Websocket chiuso in finally block.") # DEBUG if receive_task and not receive_task.cancelled(): # Controlla se receive_task è definito e non è già cancellata print(f"Status receive_task before cancel: {receive_task.cancelled()}") # DEBUG receive_task.cancel() print("Task di ricezione cancellata in finally block.") # DEBUG print(f"Status receive_task after cancel: {receive_task.cancelled()}") # DEBUG print("Finally block in connect_and_send finished.") # DEBUG return asyncio.current_task() # Return the main task # Modifica significativa qui: signal_handler now DOES accept 'task' as argument again def signal_handler(sig, frame, task): # ADDED 'task' argument back """Gestisce il segnale SIGINT (CTRL+C) per chiudere correttamente la connessione.""" print("\nRicevuto CTRL+C, chiusura della connessione WebSocket...") print("Calling task.cancel() from signal_handler") if task is not None: # Now 'task' IS passed correctly task.cancel() print("task.cancel() called.") else: print("Task is None in signal_handler (this SHOULD NOT happen now).") # This should not happen anymore if __name__ == "__main__": loop = asyncio.get_event_loop() main_task_instance = None # Variable to hold the main task instance try: main_task_instance = loop.run_until_complete(connect_and_send()) # Run and get the task except KeyboardInterrupt: # KeyboardInterrupt può essere sollevata anche se non gestita direttamente da signal pass # Gestito già dal signal handler e dalla cancellazione della task except asyncio.CancelledError: # Cattura CancelledError se la task viene cancellata print("Task connect_and_send cancelled.") # Debug message finally: # Use functools.partial to "pre-compile" the argument 'task' in the signal_handler - USE main_task_instance partial_signal_handler = functools.partial(signal_handler, task=main_task_instance) # Pass main_task_instance signal.signal(signal.SIGINT, partial_signal_handler) # Register signal handler parziale print("Applicazione client terminata.") loop.close()