95 lines
2.5 KiB
Python
95 lines
2.5 KiB
Python
import logging
|
|
import multiprocessing as mp
|
|
import socket
|
|
import time
|
|
from multiprocessing.context import Process
|
|
from multiprocessing.queues import Queue
|
|
from multiprocessing.synchronize import Event
|
|
|
|
from server import worker
|
|
|
|
|
|
class HTTPServer:
|
|
address: str
|
|
port: int
|
|
workers = []
|
|
worker_count: int
|
|
server: socket
|
|
|
|
_dispatch_queue: Queue
|
|
_stop_event: Event
|
|
|
|
def __init__(self, address: str, port: int, worker_count, logging_level):
|
|
self.address = address
|
|
self.port = port
|
|
self.worker_count = worker_count
|
|
self.logging_level = logging_level
|
|
|
|
mp.set_start_method("spawn")
|
|
self._dispatch_queue = mp.Queue()
|
|
self._stop_event = mp.Event()
|
|
|
|
def start(self):
|
|
try:
|
|
self.__do_start()
|
|
except KeyboardInterrupt:
|
|
self.__shutdown()
|
|
|
|
def __do_start(self):
|
|
# Create socket
|
|
|
|
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
self.server.bind((self.address, self.port))
|
|
|
|
self.__create_workers()
|
|
|
|
self.__listen()
|
|
|
|
def __listen(self):
|
|
|
|
self.server.listen()
|
|
logging.debug("Listening for connections")
|
|
|
|
while True:
|
|
if self._dispatch_queue.qsize() > self.worker_count:
|
|
time.sleep(0.01)
|
|
continue
|
|
|
|
conn, addr = self.server.accept()
|
|
logging.info("New connection: %s", addr[0])
|
|
self._dispatch_queue.put((conn, addr))
|
|
logging.debug("Dispatched connection %s", addr)
|
|
|
|
def __shutdown(self):
|
|
|
|
# Set stop event
|
|
self._stop_event.set()
|
|
|
|
# Wake up workers
|
|
logging.debug("Waking up workers")
|
|
for p in self.workers:
|
|
self._dispatch_queue.put((None, None))
|
|
|
|
logging.debug("Closing dispatch queue")
|
|
self._dispatch_queue.close()
|
|
|
|
logging.debug("Waiting for workers to shutdown")
|
|
p: Process
|
|
for p in self.workers:
|
|
p.join()
|
|
p.terminate()
|
|
|
|
logging.debug("Shutting down socket")
|
|
self.server.shutdown(socket.SHUT_RDWR)
|
|
self.server.close()
|
|
|
|
def __create_workers(self):
|
|
for i in range(self.worker_count):
|
|
logging.debug("Creating worker: %d", i + 1)
|
|
p = mp.Process(target=worker.worker,
|
|
args=(self.address, i + 1, self.logging_level, self._dispatch_queue, self._stop_event))
|
|
p.start()
|
|
self.workers.append(p)
|
|
|
|
time.sleep(0.1)
|