-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpart2_server.py
More file actions
167 lines (141 loc) · 5.62 KB
/
part2_server.py
File metadata and controls
167 lines (141 loc) · 5.62 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
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
154
155
156
157
158
159
160
161
162
163
164
import sys
import socket
import select
import argparse
# Dictionary
registered_clients = {}
def register(client_socket, data):
lines = data.split("\r\n")
client_id = None
client_ip = None
client_port = None
for line in lines:
if line.startswith("clientID:"):
client_id = line.split(":")[1].strip()
elif line.startswith("IP:"):
client_ip = line.split(":")[1].strip()
elif line.startswith("Port:"):
client_port = line.split(":")[1].strip()
if client_id and client_ip and client_port:
sys.stdout.write(f"REGISTER: {client_id} from {client_ip}:{client_port} received\n")
sys.stdout.flush()
registered_clients[client_id] = (client_ip, client_port)
regack_message = f"REGACK\r\nclientID: {client_id}\r\nIP: {client_ip}\r\nPort: {client_port}\r\nStatus: registered\r\n\r\n"
client_socket.sendall(regack_message.encode())
else:
sys.stdout.write("Invalid REGISTER message format\n")
sys.stdout.flush()
def bridge(client_socket, data):
requesting_client = None
requesting_client_ip = None
requesting_client_port = None
lines = data.split("\r\n")
for line in lines:
if line.startswith("clientID:"):
requesting_client = line.split(":")[1].strip()
if requesting_client in registered_clients:
requesting_client_ip, requesting_client_port = registered_clients[requesting_client]
else:
sys.stdout.write(f"Invalid BRIDGE request: Requesting client '{requesting_client}' not found\n")
sys.stdout.flush()
return
peer = None
for peer_id, (peer_ip, peer_port) in registered_clients.items():
if peer_id != requesting_client:
peer = (peer_id, peer_ip, peer_port)
break
if peer:
peer_id, peer_ip, peer_port = peer
bridgeack_message = (
f"BRIDGEACK\r\n"
f"clientID: {peer_id}\r\n"
f"IP: {peer_ip}\r\n"
f"Port: {peer_port}\r\n\r\n"
)
client_socket.sendall(bridgeack_message.encode())
sys.stdout.write(f"BRIDGE: {peer_id} {peer_ip}:{peer_port} {requesting_client} {requesting_client_ip}:{requesting_client_port}\n")
sys.stdout.flush()
else:
bridgeack_null = (
f"BRIDGEACK\r\n"
f"clientID: \r\n"
f"IP: \r\n"
f"Port: \r\n\r\n"
)
client_socket.sendall(bridgeack_null.encode())
sys.stdout.write(f"BRIDGE: {requesting_client} {requesting_client_ip}:{requesting_client_port}\n")
sys.stdout.flush()
def message(client_socket, data):
if data.startswith("REGISTER\r\n"):
register(client_socket, data)
elif data.startswith("BRIDGE\r\n"):
bridge(client_socket, data)
else:
sys.stdout.write(f"Unknown message received: {data}\n")
sys.stdout.flush()
def display_clients():
for client_id, (client_ip, client_port) in registered_clients.items():
sys.stdout.write(f"{client_id} {client_ip}:{client_port}\n")
sys.stdout.flush()
def main():
parse = argparse.ArgumentParser()
parse.add_argument('--port', type=int)
args = parse.parse_args()
try:
sv_port = args.port
if not (1<=sv_port <= 65535):
raise ValueError("Port number must be between 1 and 65535.\n")
except ValueError as e:
sys.stdout.write(f"Error: Invalid port number for Server\n")
sys.stdout.flush()
sys.exit(1)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(('127.0.0.1', sv_port))
server_socket.listen(5)
sys.stdout.write(f"Server listening on 127.0.0.1:{sv_port}\n")
sys.stdout.flush()
sockets = [server_socket, sys.stdin]
try:
while True:
# Monitor sockets for readability
readable, _, _ = select.select(sockets, [], [])
for sock in readable:
if sock is server_socket:
client_socket, addr = server_socket.accept()
sockets.append(client_socket)
elif sock is sys.stdin:
command = sys.stdin.readline().strip()
if command == "/info":
display_clients()
else:
continue
else:
try:
data = sock.recv(1024).decode().strip()
if data:
message(sock, data)
else:
sockets.remove(sock)
sock.close()
except Exception as e:
sys.stdout.write(f"Error: {e}")
sys.stdout.flush();
sockets.remove(sock)
sock.close()
except KeyboardInterrupt:
sys.stdout.write("select(): Interrupted system call\n")
sys.stdout.flush()
finally:
server_socket.close()
if __name__ == "__main__":
main()
"""
Citations
- Used help from Chatgpt in understanding select() and
how exactly select works(because I have never used select() before this assignment)
- Used the Socket Programming in Python(Guide) and the textbook
for guidance with understanding how socket programming actually worked, because
before this class I've also never even heard about socket programming.
- Used ChatGpt to understand the process of storing items in a dictionary
"""