#!/usr/bin/env python3.7
|
|
import socket # socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR
|
|
import logging
|
|
import threading
|
|
import ClientConnection
|
|
|
|
|
|
class Server(object):
|
|
"""
|
|
A simple chat application server
|
|
"""
|
|
clients = []
|
|
|
|
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
|
|
def __init__(self, host: str, port: int, maxClients=64):
|
|
self.host = host
|
|
self.port = port
|
|
self.soc.bind((host, port))
|
|
self.maxClients = maxClients
|
|
|
|
def run(self) -> None:
|
|
"""
|
|
Start the server and start to listen for incoming connection
|
|
"""
|
|
self.soc.listen(self.maxClients)
|
|
logging.info('Start listening on {}:{} maximum {} clients'.format(
|
|
self.host, self.port, self.maxClients))
|
|
while True:
|
|
conn, addr = self.soc.accept()
|
|
client = ClientConnection.ClientConnection(self, conn, addr)
|
|
msg = '{} has joined the chat.'.format(client.addr)
|
|
self._announce(msg)
|
|
self.clients.append(client)
|
|
t = threading.Thread(target=client.serve)
|
|
t.daemon = True
|
|
t.start()
|
|
|
|
def removeClient(self, client: ClientConnection.ClientConnection) -> None:
|
|
"""
|
|
Remove client from this server list of connected clients
|
|
"""
|
|
msg = '{} has left the chat.'.format(client.nameFormat())
|
|
self.clients.remove(client)
|
|
self._announce(msg)
|
|
|
|
def _announce(self, announcement: str) -> None:
|
|
"""
|
|
Send announcement from system to all connected clients
|
|
"""
|
|
msg = '[system] {}'.format(announcement)
|
|
logging.info(msg)
|
|
for client in self.clients:
|
|
client.send(msg)
|
|
|
|
def sendToAll(self, sender: ClientConnection.ClientConnection, msg: str) -> None:
|
|
"""
|
|
Broadcast message from one client to other clients
|
|
"""
|
|
msg = '{} {}'.format(sender.nameFormat(), msg)
|
|
logging.info(msg)
|
|
for client in self.clients:
|
|
if client != sender:
|
|
client.send(msg)
|