# compatibile Windows 11 # compatibile Ubuntu 24.10 # compatibile python 3.12.7 import socket import sys import time import signal import os import threading import errno # Importa il modulo errno class UDPServer: def __init__(self, host, port, svrhost=None, svrport=None): self.host = host self.port = port self.svrhost = svrhost if svrhost is not None else host self.svrport = svrport if svrport is not None else port self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.setblocking(False) self.sock.bind((self.host, self.port)) self.active = False self.on_message = None self.on_error = None self.on_start = None self.on_stop = None self._stop_event = False self._input_buffer = "" self._input_lock = threading.Lock() self._input_thread = None def start(self): if not self.active: self.active = True if self.on_start: self.on_start(self) self._input_thread = threading.Thread(target=self._input_loop, daemon=True) self._input_thread.start() def send_to(self, message, address=None): if address is None: address = (self.svrhost, self.svrport) try: self.sock.sendto(message, address) except Exception as e: if self.on_error: self.on_error(self, str(e)) def close(self): if self.active: self._stop_event = True self.active = False if self._input_thread: self._input_thread.join() self.sock.close() if self.on_stop: self.on_stop(self) def _input_loop(self): """Ciclo eseguito nel thread separato per leggere l'input.""" while not self._stop_event: try: ch = sys.stdin.read(1) with self._input_lock: if ch == '\n' or ch == '\r': if self._input_buffer: self.send_to((self._input_buffer + '\r\n').encode('utf-8')) self._input_buffer = "" print() elif ch == '\b' or ord(ch) == 127: if self._input_buffer: self._input_buffer = self._input_buffer[:-1] print('\b \b', end='', flush=True) else: self._input_buffer += ch print(ch, end='', flush=True) except Exception as e: if self.on_error and not self._stop_event: self.on_error(self, str(e)) break time.sleep(0.01) def run(self): """Ciclo principale del server.""" self.start() try: while self.active and not self._stop_event: try: data, address = self.sock.recvfrom(1024) if self.on_message: self.on_message(self, data.decode('utf-8', 'replace'), address) except socket.error as e: # Usa errno.EWOULDBLOCK (o errno.EAGAIN, che sono equivalenti) if e.errno != errno.EWOULDBLOCK: if self.on_error: self.on_error(self, str(e)) time.sleep(0.01) except KeyboardInterrupt: print("\nInterrotto dall'utente (Ctrl+C).") finally: self.close() # --- Funzioni di callback (invariate) --- def handle_message(server, message, address): print(f"Ricevuto da {address}: {message}") res = "ACK" server.send_to(res.encode('utf-8'), address) def handle_error(server, message): print(f"Errore: {message}") def handle_start(server): print("Server UDP avviato.") def handle_stop(server): print("Server UDP fermato.") # --- Gestione dei segnali --- def signal_handler(sig, frame): global server print("\nSegnale ricevuto. Chiusura in corso...") if server: server.close() sys.exit(0) if __name__ == '__main__': server = UDPServer(host='localhost', port=5000, svrhost='localhost', svrport=5001) server.on_message = handle_message server.on_error = handle_error server.on_start = handle_start server.on_stop = handle_stop signal.signal(signal.SIGINT, signal_handler) if os.name != 'nt': signal.signal(signal.SIGTERM, signal_handler) server.run()