From ed6ecc548b48bbd9d9a1204ecb438e8716d1ab00 Mon Sep 17 00:00:00 2001 From: sirmrak Date: Thu, 21 May 2026 13:19:59 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20start=5Fserver.py=20=E2=80=94=20=D0=B8?= =?UTF-8?q?=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=B2=D0=B5=D1=80=D1=88=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF?= =?UTF-8?q?=D0=BE=20Ctrl+C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проблемы: - signal_handler блокировал shutdown() - Порт не освобождался после Ctrl+C - Невозможно было перезапустить сервер Решения: - Убран signal_handler — используется KeyboardInterrupt - shutdown() вызывается в отдельном потоке (avoid deadlock) - with контекст для автоматического закрытия - allow_reuse_address = True для быстрого рестарта - Обработка OSError при занятом порте --- web-client/start_server.py | 59 +++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/web-client/start_server.py b/web-client/start_server.py index b794edb..17646bf 100755 --- a/web-client/start_server.py +++ b/web-client/start_server.py @@ -13,16 +13,13 @@ import argparse import http.server import socketserver import os -import signal import sys +import threading from pathlib import Path PORT = 8080 SCRIPT_DIR = Path(__file__).parent.resolve() -# Global server reference for cleanup -httpd = None - class CustomHandler(http.server.SimpleHTTPRequestHandler): """Custom handler with better logging.""" @@ -36,32 +33,20 @@ class CustomHandler(http.server.SimpleHTTPRequestHandler): pass -def signal_handler(sig, frame): - """Handle Ctrl+C gracefully.""" - print("\n👋 Shutting down...") - if httpd: - # Use shutdown() to stop serve_forever() - httpd.shutdown() +class ReusableTCPServer(socketserver.TCPServer): + """TCP Server with address reuse enabled.""" + allow_reuse_address = True def main(): - global httpd - parser = argparse.ArgumentParser(description='WebSocket Client Web Server') parser.add_argument('--port', type=int, default=PORT, help=f'Port (default: {PORT})') parser.add_argument('--host', default='0.0.0.0', help='Host (default: 0.0.0.0)') args = parser.parse_args() - # Change to websocket-service directory + # Change to script directory os.chdir(SCRIPT_DIR) - # Register signal handlers - signal.signal(signal.SIGINT, signal_handler) - signal.signal(signal.SIGTERM, signal_handler) - - # Allow socket reuse - socketserver.TCPServer.allow_reuse_address = True - print(f""" ╔══════════════════════════════════════════════════════════╗ ║ 🛰️ Wyoming Satellite WebSocket Client Server ║ @@ -74,16 +59,32 @@ def main(): ╚══════════════════════════════════════════════════════════╝ """) - httpd = socketserver.TCPServer((args.host, args.port), CustomHandler) - print(f"🚀 Server started on http://{args.host}:{args.port}") - try: - httpd.serve_forever() - except KeyboardInterrupt: - pass - finally: - print("\n👋 Server stopped") - httpd.server_close() + with ReusableTCPServer((args.host, args.port), CustomHandler) as httpd: + print(f"🚀 Server started on http://{args.host}:{args.port}") + print("📖 Serving files from:", SCRIPT_DIR) + print("\n⌨️ Press Ctrl+C to stop\n") + + try: + httpd.serve_forever() + except KeyboardInterrupt: + print("\n👋 Shutting down gracefully...") + # Shutdown in a separate thread to avoid deadlock + shutdown_thread = threading.Thread(target=httpd.shutdown) + shutdown_thread.start() + shutdown_thread.join(timeout=2) + httpd.server_close() + print("✅ Server stopped successfully") + + except OSError as e: + print(f"\n❌ Error: Could not bind to port {args.port}") + print(f" {e}") + print("\n💡 Try using a different port:") + print(f" python3 {sys.argv[0]} --port 8081\n") + sys.exit(1) + except Exception as e: + print(f"\n❌ Unexpected error: {e}") + sys.exit(1) if __name__ == "__main__":