This repository has been archived by the owner on Mar 7, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
udpserver.py
153 lines (122 loc) · 5.25 KB
/
udpserver.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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# Implement a UDP server
import json
import socket
# Create a UDP socket
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Bind the socket to the port
SERVER_ADDRESS = ('localhost', 9999)
print('starting up on %s port %s' % SERVER_ADDRESS)
server.bind(SERVER_ADDRESS)
clients = {} # {address: handle}
while True:
print('waiting to receive message')
data, address = server.recvfrom(1024)
print('received %s bytes from %s' % (len(data), address))
print(data)
# echo for debug
# sent = server.sendto(data, address)
# print('sent %s bytes back to %s' % (sent, address))
# Responses to commands
try:
data_json = json.loads(data.decode())
except json.decoder.JSONDecodeError: # Will also catch empty string (bytes)
print('Error: Invalid JSON')
continue
# Every valid JSON input should have a 'command' key. We will not check for its presence.
else:
# Note: Do not specify command syntax in error messages. The server doesn't know how the client parses commands.
if data_json['command'] == 'join':
# update clients
clients.update({address: None})
print('clients:', clients)
# inform sender of success
response = json.dumps({'command': 'info', 'message': 'Connection to the Message Board Server is successful! Please register.'})
server.sendto(response.encode(), address)
elif data_json['command'] == 'leave':
# broadcast to all clients
response = json.dumps({'command': 'info', 'message': f'{handle} left the chat'}).encode() #pre
for client in clients:
server.sendto(response, client)
# update clients
clients.pop(address) # will remove regardless of whether handle is registered
print('clients:', clients)
# inform sender of success
response = json.dumps({'command': 'info', 'message': 'You have left the Message Board Server.'})
server.sendto(response.encode(), address)
elif data_json['command'] == 'register':
handle = data_json['handle']
if clients.get(address) is not None:
print('Error: Already registered')
# inform sender of error
response = json.dumps({'command': 'error', 'message': 'Already registered.'})
server.sendto(response.encode(), address)
continue
# check if handle already exists
if handle in clients.values():
print('Error: Handle already exists')
# inform sender of error
response = json.dumps({'command': 'error', 'message': 'Registration failed. Handle is taken.'})
server.sendto(response.encode(), address)
continue
# update clients
clients.update({address: handle})
print('clients:', clients)
# broadcast to all clients
response = json.dumps({'command': 'info', 'message': f'{handle} joined the chat'}).encode() #pre-encode response
for client_address in clients:
server.sendto(response, client_address)
# inform sender of success
response = json.dumps({'command': 'info', 'message': f"Welcome {handle}!"})
server.sendto(response.encode(), address)
# below this line, handle must be registered
# error check if not registered
elif clients.get(address) is None:
print('Error: Not registered')
# inform sender of error
response = json.dumps({'command': 'error', 'message': 'Not registered.'})
server.sendto(response.encode(), address)
continue
elif data_json['command'] == 'list':
# get list of handles
handle_list = list(clients.values())
# send list of handles
response = json.dumps({'command': 'info', 'message': f"List of users: {', '.join(handle_list)}"})
server.sendto(response.encode(), address)
elif data_json['command'] == 'msg':
# Note: Allow the sender to send a message to themselves
destination_handle = data_json['handle']
print('destination_handle:', destination_handle)
try:
destination_addr = list(clients.keys())[list(clients.values()).index(destination_handle)]
except ValueError:
destination_addr = None
print('destination_addr:', destination_addr)
source_handle = clients.get(address)
print('source_handle:', source_handle)
# error check if handle exists
if not destination_addr:
print('Error: Invalid handle')
# inform sender of error
response = json.dumps({'command': 'error', 'message': 'Handle not found'})
server.sendto(response.encode(), address)
continue
# change handle to source handle and send to destination
data_json.update({'handle': source_handle})
response = json.dumps(data_json)
server.sendto(response.encode(), destination_addr)
# inform sender of success
response = json.dumps({'command': 'info', 'message': f"[To {destination_handle}]: {data_json['message']}"})
server.sendto(response.encode(), address)
elif data_json['command'] == 'all':
# Note: Unlike 'msg' where the sender can only send to registered clients,
# 'all' will the sender can send to all clients (including unregistered clients)
# This behavior is okay.
print('destination_addr:', "ALL")
source_handle = clients.get(address)
print('source_handle:', source_handle)
# change handle to source handle and send to All destinations
data_json.update({'handle': source_handle})
response = json.dumps(data_json).encode() #pre-encode response
for client_address in clients:
server.sendto(response, client_address)
# sender was already informed of success in the above loop