-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.py
More file actions
95 lines (80 loc) · 3.02 KB
/
server.py
File metadata and controls
95 lines (80 loc) · 3.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
"""Entry point for the multi-threaded HTTP server assignment implementation."""
from __future__ import annotations
import socket
import sys
import threading
import time
from server_core.config import (
DEFAULT_HOST,
DEFAULT_PORT,
DEFAULT_MAX_THREADS,
BACKLOG,
MAX_QUEUE,
RESOURCES_DIR,
)
from server_core.thread_pool import ThreadPool
from server_core.utils import log
from server_core.http_response import build_response
from server_core.worker import handle_connection
def _parse_args() -> tuple[str, int, int]:
host = DEFAULT_HOST
port = DEFAULT_PORT
max_threads = DEFAULT_MAX_THREADS
if len(sys.argv) > 1:
try:
port = int(sys.argv[1])
except ValueError:
log(f"Invalid port '{sys.argv[1]}', using default {port}")
if len(sys.argv) > 2:
host = sys.argv[2]
if len(sys.argv) > 3:
try:
max_threads = int(sys.argv[3])
except ValueError:
log(f"Invalid max thread count '{sys.argv[3]}', using default {max_threads}")
return host, port, max_threads
def _monitor(pool: ThreadPool, stop_event: threading.Event) -> None:
while not stop_event.is_set():
time.sleep(15)
log(f"Thread pool status: queue={pool.queue_size()} workers={pool.max_workers}")
def main() -> None:
host, port, max_threads = _parse_args()
pool = ThreadPool(max_threads, MAX_QUEUE)
stop_event = threading.Event()
monitor_thread = threading.Thread(target=_monitor, args=(pool, stop_event), daemon=True)
monitor_thread.start()
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_sock:
server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_sock.bind((host, port))
server_sock.listen(BACKLOG)
log(f"HTTP Server started on http://{host}:{port}")
log(f"Thread pool size: {max_threads}")
log(f"Serving files from '{RESOURCES_DIR}'")
log("Press Ctrl+C to stop the server")
try:
while True:
client_sock, client_addr = server_sock.accept()
log(f"Connection from {client_addr}")
submitted = pool.submit(handle_connection, client_sock, client_addr, host, port)
if not submitted:
log("Warning: Thread pool saturated, returning 503")
try:
response = build_response(
503,
{"Content-Type": "text/plain", "Retry-After": "5"},
b"503 Service Unavailable",
False,
0,
)
client_sock.sendall(response)
except Exception:
pass
finally:
client_sock.close()
except KeyboardInterrupt:
log("Shutdown requested by user")
finally:
stop_event.set()
pool.stop()
if __name__ == "__main__":
main()