-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathserver.py
106 lines (82 loc) · 3.52 KB
/
server.py
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
import socket, threading
# Global variable that mantain client's connections
connections = []
def handle_user_connection(connection: socket.socket, address: str) -> None:
'''
Get user connection in order to keep receiving their messages and
sent to others users/connections.
'''
while True:
try:
# Get client message
msg = connection.recv(1024)
# If no message is received, there is a chance that connection has ended
# so in this case, we need to close connection and remove it from connections list.
if msg:
# Log message sent by user
print(f'{address[0]}:{address[1]} - {msg.decode()}')
# Build message format and broadcast to users connected on server
msg_to_send = f'From {address[0]}:{address[1]} - {msg.decode()}'
broadcast(msg_to_send, connection)
# Close connection if no message was sent
else:
remove_connection(connection)
break
except Exception as e:
print(f'Error to handle user connection: {e}')
remove_connection(connection)
break
def broadcast(message: str, connection: socket.socket) -> None:
'''
Broadcast message to all users connected to the server
'''
# Iterate on connections in order to send message to all client's connected
for client_conn in connections:
# Check if isn't the connection of who's send
if client_conn != connection:
try:
# Sending message to client connection
client_conn.send(message.encode())
# if it fails, there is a chance of socket has died
except Exception as e:
print('Error broadcasting message: {e}')
remove_connection(client_conn)
def remove_connection(conn: socket.socket) -> None:
'''
Remove specified connection from connections list
'''
# Check if connection exists on connections list
if conn in connections:
# Close socket connection and remove connection from connections list
conn.close()
connections.remove(conn)
def server() -> None:
'''
Main process that receive client's connections and start a new thread
to handle their messages
'''
LISTENING_PORT = 12000
try:
# Create server and specifying that it can only handle 4 connections by time!
socket_instance = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_instance.bind(('', LISTENING_PORT))
socket_instance.listen(4)
print('Server running!')
while True:
# Accept client connection
socket_connection, address = socket_instance.accept()
# Add client connection to connections list
connections.append(socket_connection)
# Start a new thread to handle client connection and receive it's messages
# in order to send to others connections
threading.Thread(target=handle_user_connection, args=[socket_connection, address]).start()
except Exception as e:
print(f'An error has occurred when instancing socket: {e}')
finally:
# In case of any problem we clean all connections and close the server connection
if len(connections) > 0:
for conn in connections:
remove_connection(conn)
socket_instance.close()
if __name__ == "__main__":
server()