This repository was archived by the owner on Mar 7, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathserver.py
More file actions
111 lines (90 loc) · 4.53 KB
/
server.py
File metadata and controls
111 lines (90 loc) · 4.53 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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/env python3
import socket
import threading
import logging
from config import Settings
class Server:
connections: list[socket.socket] = [] # Clients' Socket List.
serverSocket: socket.socket = None # Server's Socket.
def __init__(self) -> None:
'''
Initializes the Server.
'''
try:
logging.basicConfig(level=logging.NOTSET, format='[SERVER - %(levelname)s] %(message)s') # Initialize Logging.
# Create the Server's Socket and bind it to an address and a port.
# Then give a maximum of simultaneous connections.
Server.serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Server.serverSocket.bind((Settings.SERVER_ADDRESS, Settings.SERVER_PORT))
Server.serverSocket.listen(Settings.MAX_NUMBER_OF_CLIENTS)
logging.info('Server started!')
# Accepting Clients infinite loop.
while True:
serverConnection, address = Server.serverSocket.accept()
Server.connections.append((serverConnection, address))
# Broadcast the entry message.
entryMessage = f'[{address[0]}:{address[1]}] has entered the server.'
Server.broadcast(entryMessage, serverConnection)
logging.info(entryMessage)
# Start Client management.
threading.Thread(target=Server.manageClient, args=[serverConnection, address]).start()
except RuntimeError as e:
logging.error(f'Error occurred when creating user thread: {e}.', exc_info=Settings.EXCEPTIONS_INFO)
except Exception as e:
logging.error(f'Error occurred when creating socket: {e}.', exc_info=Settings.EXCEPTIONS_INFO)
finally:
# If there are users connected, remove them.
if Server.connections:
for conn, addr in Server.connections:
Server.removeClient(conn, addr)
@staticmethod
def manageClient(connection: socket.socket, address: str) -> None:
'''
Send and receive messages from all the users.
'''
# Clients messages handling infinite loop.
while True:
try:
receivedMessage = connection.recv(Settings.BUFFER_SIZE)
if receivedMessage:
sendingMessage = f'[{address[0]}:{address[1]}] {receivedMessage.decode(Settings.MESSAGE_ENCODING)}'
logging.info(sendingMessage)
Server.broadcast(sendingMessage, connection)
else:
Server.removeClient(connection, address)
break
except Exception as e:
logging.error(f'Error occured while handling client {address} connection: {e}.', exc_info=Settings.EXCEPTIONS_INFO)
Server.removeClient(connection, address)
break
@staticmethod
def broadcast(message: str, connection: socket.socket) -> None:
'''
Send message to all clients.
'''
# Send a broadcast message, cycling through all clients.
for clientConnection, _ in Server.connections:
try:
clientConnection.send(message.encode(Settings.MESSAGE_ENCODING))
except Exception as e:
logging.error(f'Error occured while broadcasting message to client {_}: {e}.', exc_info=Settings.EXCEPTIONS_INFO)
Server.removeClient(clientConnection, _)
@staticmethod
def removeClient(connection: socket.socket, address: str) -> None:
'''
Remove client from the connection list.
'''
# Removes the selected client from the connections list,
# then send a broadcast message with that information.
if connection in [c for c, _ in Server.connections]:
connection.close()
Server.connections = [(c, addr) for c, addr in Server.connections if c != connection]
leavingMessage: str = f'[{address[0]}:{address[1]}] has left the server.'
Server.broadcast(leavingMessage, connection)
logging.info(leavingMessage)
# If all users are gone, then close the server.
if Server.serverSocket and not Server.connections:
Server.serverSocket.close()
logging.info('Server closed!')
if __name__ == "__main__":
Server()