You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
2.7 KiB
Python
98 lines
2.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
import json
|
|
import socket
|
|
import sys
|
|
import threading
|
|
import model
|
|
|
|
|
|
BUFFER_SIZE = 2 ** 10
|
|
CLOSING = "Application closing..."
|
|
CONNECTION_ABORTED = "Connection aborted"
|
|
CONNECTED_PATTERN = "Client connected: {}:{}"
|
|
ERROR_ARGUMENTS = "Provide port number as the first command line argument"
|
|
ERROR_OCCURRED = "Error Occurred"
|
|
EXIT = "exit"
|
|
JOIN_PATTERN = "{username} has joined"
|
|
RUNNING = "Server is running..."
|
|
SERVER = "SERVER"
|
|
SHUTDOWN_MESSAGE = "shutdown"
|
|
TYPE_EXIT = "Type 'exit' to exit>"
|
|
|
|
|
|
class Server(object):
|
|
|
|
def __init__(self, argv):
|
|
self.clients = set()
|
|
self.listen_thread = None
|
|
self.port = None
|
|
self.sock = None
|
|
self.parse_args(argv)
|
|
|
|
def listen(self):
|
|
self.sock.listen(1)
|
|
while True:
|
|
try:
|
|
client, address = self.sock.accept()
|
|
except OSError:
|
|
print(CONNECTION_ABORTED)
|
|
return
|
|
print(CONNECTED_PATTERN.format(*address))
|
|
self.clients.add(client)
|
|
threading.Thread(target=self.handle, args=(client,)).start()
|
|
|
|
def handle(self, client):
|
|
while True:
|
|
try:
|
|
message = model.Message(**json.loads(self.receive(client)))
|
|
except (ConnectionAbortedError, ConnectionResetError):
|
|
print(CONNECTION_ABORTED)
|
|
return
|
|
if message.quit:
|
|
client.close()
|
|
self.clients.remove(client)
|
|
return
|
|
print(str(message))
|
|
if SHUTDOWN_MESSAGE.lower() == message.message.lower():
|
|
self.exit()
|
|
return
|
|
self.broadcast(message)
|
|
|
|
def broadcast(self, message):
|
|
for client in self.clients:
|
|
client.sendall(message.marshal())
|
|
|
|
def receive(self, client):
|
|
buffer = ""
|
|
while not buffer.endswith(model.END_CHARACTER):
|
|
buffer += client.recv(BUFFER_SIZE).decode(model.TARGET_ENCODING)
|
|
return buffer[:-1]
|
|
|
|
def run(self):
|
|
print(RUNNING)
|
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
self.sock.bind(("", self.port))
|
|
self.listen_thread = threading.Thread(target=self.listen)
|
|
self.listen_thread.start()
|
|
|
|
def parse_args(self, argv):
|
|
if len(argv) != 2:
|
|
raise RuntimeError(ERROR_ARGUMENTS)
|
|
try:
|
|
self.port = int(argv[1])
|
|
except ValueError:
|
|
raise RuntimeError(ERROR_ARGUMENTS)
|
|
|
|
def exit(self):
|
|
self.sock.close()
|
|
for client in self.clients:
|
|
client.close()
|
|
print(CLOSING)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
Server(sys.argv).run()
|
|
except RuntimeError as error:
|
|
print(ERROR_OCCURRED)
|
|
print(str(error)) |