fix: start_server.py — исправлено завершение по Ctrl+C
Проблемы: - signal_handler блокировал shutdown() - Порт не освобождался после Ctrl+C - Невозможно было перезапустить сервер Решения: - Убран signal_handler — используется KeyboardInterrupt - shutdown() вызывается в отдельном потоке (avoid deadlock) - with контекст для автоматического закрытия - allow_reuse_address = True для быстрого рестарта - Обработка OSError при занятом порте
This commit is contained in:
+25
-24
@@ -13,16 +13,13 @@ import argparse
|
|||||||
import http.server
|
import http.server
|
||||||
import socketserver
|
import socketserver
|
||||||
import os
|
import os
|
||||||
import signal
|
|
||||||
import sys
|
import sys
|
||||||
|
import threading
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
PORT = 8080
|
PORT = 8080
|
||||||
SCRIPT_DIR = Path(__file__).parent.resolve()
|
SCRIPT_DIR = Path(__file__).parent.resolve()
|
||||||
|
|
||||||
# Global server reference for cleanup
|
|
||||||
httpd = None
|
|
||||||
|
|
||||||
|
|
||||||
class CustomHandler(http.server.SimpleHTTPRequestHandler):
|
class CustomHandler(http.server.SimpleHTTPRequestHandler):
|
||||||
"""Custom handler with better logging."""
|
"""Custom handler with better logging."""
|
||||||
@@ -36,32 +33,20 @@ class CustomHandler(http.server.SimpleHTTPRequestHandler):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def signal_handler(sig, frame):
|
class ReusableTCPServer(socketserver.TCPServer):
|
||||||
"""Handle Ctrl+C gracefully."""
|
"""TCP Server with address reuse enabled."""
|
||||||
print("\n👋 Shutting down...")
|
allow_reuse_address = True
|
||||||
if httpd:
|
|
||||||
# Use shutdown() to stop serve_forever()
|
|
||||||
httpd.shutdown()
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
global httpd
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='WebSocket Client Web Server')
|
parser = argparse.ArgumentParser(description='WebSocket Client Web Server')
|
||||||
parser.add_argument('--port', type=int, default=PORT, help=f'Port (default: {PORT})')
|
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)')
|
parser.add_argument('--host', default='0.0.0.0', help='Host (default: 0.0.0.0)')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Change to websocket-service directory
|
# Change to script directory
|
||||||
os.chdir(SCRIPT_DIR)
|
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"""
|
print(f"""
|
||||||
╔══════════════════════════════════════════════════════════╗
|
╔══════════════════════════════════════════════════════════╗
|
||||||
║ 🛰️ Wyoming Satellite WebSocket Client Server ║
|
║ 🛰️ Wyoming Satellite WebSocket Client Server ║
|
||||||
@@ -74,16 +59,32 @@ def main():
|
|||||||
╚══════════════════════════════════════════════════════════╝
|
╚══════════════════════════════════════════════════════════╝
|
||||||
""")
|
""")
|
||||||
|
|
||||||
httpd = socketserver.TCPServer((args.host, args.port), CustomHandler)
|
try:
|
||||||
|
with ReusableTCPServer((args.host, args.port), CustomHandler) as httpd:
|
||||||
print(f"🚀 Server started on http://{args.host}:{args.port}")
|
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:
|
try:
|
||||||
httpd.serve_forever()
|
httpd.serve_forever()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
print("\n👋 Shutting down gracefully...")
|
||||||
finally:
|
# Shutdown in a separate thread to avoid deadlock
|
||||||
print("\n👋 Server stopped")
|
shutdown_thread = threading.Thread(target=httpd.shutdown)
|
||||||
|
shutdown_thread.start()
|
||||||
|
shutdown_thread.join(timeout=2)
|
||||||
httpd.server_close()
|
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__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user