-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMCTCPServer.py
More file actions
147 lines (133 loc) · 6.66 KB
/
MCTCPServer.py
File metadata and controls
147 lines (133 loc) · 6.66 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
from socket import socket, AF_INET, SOCK_STREAM, SHUT_RDWR, timeout, SOCK_DGRAM, error, gethostname, gethostbyname
from BMI import BMI
from db import ServerDB
import selectors
import types
from TCPServer import get_local_IP
import hashlib
class MultiConnectionServer:
def __init__(self, host, port):
self.host = host
self.port = port
self.bmiCal = BMI()
self.dataBase = ServerDB()
# initiate a default selector to handle multiple connections
self.sel = selectors.DefaultSelector()
self.chatLoop()
def checkCredentials(self, username, password):
result = self.dataBase.select_user_by_name((username))
if result == 'notFound': # create new entry
self.dataBase.create_user((username, password, -99.99))
return 'new', -99.99
else:
storedPassword = result[1]
oldBmi = result[-1]
if storedPassword == password:
return 'success', oldBmi
else:
return 'fail', -99.99
def accept_wrapper(self, sock):
# Since the listening socket was registered for the event selectors.EVENT_READ,
# it should be ready to read. We call sock.accept()
conn, addr = sock.accept() # Should be ready to read
print("accepted connection from", addr)
conn.setblocking(False)
# we create an object to hold the data we want included along with the socket
data = types.SimpleNamespace(addr=addr, inb=b"", outb=b"")
# Since we want to know when the client connection is ready for reading and writing,
# both of those events are set in the events mask.
events = selectors.EVENT_READ | selectors.EVENT_WRITE
# then we register this connection to the selector
self.sel.register(conn, events, data=data)
def service_connection(self, key, mask):
# key is the namedtuple returned from select() that contains the socket object (fileobj) and data object.
sock = key.fileobj
data = key.data
if mask & selectors.EVENT_READ:
# If the socket is ready for reading, then mask & selectors.EVENT_READ is true, and sock.recv() is called
recv_data = sock.recv(1024) # Should be ready to read
if recv_data:
# Any data that’s read is appended to data.outb so it can be sent later.
data.outb = recv_data
else:
# This means that the client has closed their socket, so the server should too.
print("closing connection to", data.addr)
self.sel.unregister(sock)
sock.close()
if mask & selectors.EVENT_WRITE:
# When the socket is ready for writing,
# which should always be the case for a healthy socket,
# any received data stored in data.outb is processed and the answer is sent to the client
if data.outb:
print("processing", repr(data.outb), "to", data.addr)
dataTosend = self.process_message(data.outb.decode())
# Should be ready to write
sent = sock.send(dataTosend.encode())
# The bytes sent are then removed from the send buffer
data.outb = None
def process_message(self, message) -> str:
print(f"message structure: {message}")
if type(message) != str:
message = message.decode()
message_words = message.replace(" ", "").split(",")
print(message_words)
if len(message_words) > 0:
if message_words[0] == "user_password":
print("user and pass mode")
user_name, password = message_words[1:]
statFlag, oldBmi = self.checkCredentials(user_name, password)
statFlag = "status,"+statFlag
return statFlag
elif message_words[0] == "body_info":
weight, height, username = message_words[1:]
bmi, catagory = self.bmiCal.notify(int(weight), int(height))
self.dataBase.update_user((bmi, username))
return(f'result,{bmi},{catagory}')
else:
print("strange message structure")
else:
print("empty message")
return message
def chatLoop(self, host=None, port=None):
if host == None:
host = self.host
if port == None:
port = self.port
lsock = socket(AF_INET, SOCK_STREAM)
lsock.bind((host, port))
lsock.listen()
print("listening on", (host, port))
# configure the socket in non-blocking mode
# so, calls made to this socket will no longer block
lsock.setblocking(False)
# registering the socket to be monitored with sel.select() for the events we are interested in.
# For the listening socket, we want read events --> selectors.EVENT_READ
self.sel.register(lsock, selectors.EVENT_READ, data=None)
try:
while True:
# blocks until there are sockets ready for I/O
events = self.sel.select(timeout=None)
# It returns a list of (key, events masks--> read or write or both) tuples, one for each socket.
for key, mask in events:
# key is a SelectorKey namedtuple that contains a fileobj attribute.
# key.fileobj is the socket object, and mask is an event mask of the operations that are ready.
if key.data is None:
# print("wrapper called")
# then we know it’s from the listening socket and we need to accept() the connection.
self.accept_wrapper(key.fileobj)
# this wrapper function gets the new socket object and register it with the selector.
else:
# if key.data is not None, then we know it’s a client socket that’s already been accepted, and we need to service it.
# service_connection() is then called and passed key and mask,
# which contains everything we need to operate on the socket.
self.service_connection(key, mask)
except KeyboardInterrupt:
print("caught keyboard interrupt, exiting")
finally:
self.sel.close()
if __name__ == "__main__":
# ------------------------ multiple connection server ------------------------ #
print(f'ip : {get_local_IP()}')
host, port = (get_local_IP(), 22222)
MultiServer = MultiConnectionServer(host, port)
# ---------------------------------------------------------------------------- #