-
Notifications
You must be signed in to change notification settings - Fork 2
/
client.py
127 lines (105 loc) · 4.05 KB
/
client.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
import socket
import time
import select
import queue
from gui import *
ENCODING = 'utf-8'
HOST = 'localhost'
PORT = 8888
class Client(threading.Thread):
def __init__(self, host, port):
super().__init__(daemon=True, target=self.run)
self.host = host
self.port = port
self.sock = None
self.connected = self.connect_to_server()
self.buffer_size = 1024
self.queue = queue.Queue()
self.lock = threading.RLock()
self.login = ''
self.target = ''
self.login_list = []
if self.connected:
self.gui = GUI(self)
self.start()
self.gui.start()
# Only gui is non-daemon thread, therefore after closing gui app will quit
def connect_to_server(self):
"""Connect to server via socket interface, return (is_connected)"""
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((str(self.host), int(self.port)))
except ConnectionRefusedError:
print("Server is inactive, unable to connect")
return False
return True
def run(self):
"""Handle client-server communication using select module"""
inputs = [self.sock]
outputs = [self.sock]
while inputs:
try:
read, write, exceptional = select.select(inputs, outputs, inputs)
# if server unexpectedly quits, this will raise ValueError exception (file descriptor < 0)
except ValueError:
print('Server error')
GUI.display_alert('Server error has occurred. Exit app')
self.sock.close()
break
if self.sock in read:
with self.lock:
try:
data = self.sock.recv(self.buffer_size)
except socket.error:
print("Socket error")
GUI.display_alert('Socket error has occurred. Exit app')
self.sock.close()
break
self.process_received_data(data)
if self.sock in write:
if not self.queue.empty():
data = self.queue.get()
self.send_message(data)
self.queue.task_done()
else:
time.sleep(0.05)
if self.sock in exceptional:
print('Server error')
GUI.display_alert('Server error has occurred. Exit app')
self.sock.close()
break
def process_received_data(self, data):
"""Process received message from server"""
if data:
message = data.decode(ENCODING)
message = message.split('\n')
for msg in message:
if msg != '':
msg = msg.split(';')
if msg[0] == 'msg':
text = msg[1] + ' >> ' + msg[3] + '\n'
print(msg)
self.gui.display_message(text)
# if chosen login is already in use
if msg[2] != self.login and msg[2] != 'ALL':
self.login = msg[2]
elif msg[0] == 'login':
self.gui.main_window.update_login_list(msg[1:])
def notify_server(self, action, action_type):
"""Notify server if action is performed by client"""
self.queue.put(action)
if action_type == "login":
self.login = action.decode(ENCODING).split(';')[1]
elif action_type == "logout":
self.sock.close()
def send_message(self, data):
""""Send encoded message to server"""
with self.lock:
try:
self.sock.send(data)
except socket.error:
self.sock.close()
GUI.display_alert('Server error has occurred. Exit app')
# Create new client with (IP, port)
if __name__ == '__main__':
Client(HOST, PORT)