Skip to content

Commit db63dc3

Browse files
author
root
committed
Add a GUI for client and encryption
1 parent eaa47a3 commit db63dc3

File tree

4 files changed

+225
-159
lines changed

4 files changed

+225
-159
lines changed

README

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,12 @@ localhost.
1212
The client also using multithreading to work. One thread is for receiving and handling data from the
1313
server, and another thread is for accepting user input and send commands to the server.
1414

15+
[O]Nothing changed in the server code
16+
[+]Changed: code is now python 3-compatible, with slight modification due to socket data being transmitted as bytes, not raw string.
17+
[+]Updated: User program now has a GUI, implemented using PyQt
18+
[+]Added encryption to make the conversation secure. However the shared key is explicitly included
19+
[-]Issue: the main chat window will be refreshed when new text is entered or when the user highlight the chat with the cursor
20+
[-]this is due to the conflict of python thread and PyQt object
21+
[-]can be fixed but will need to change from python thread to QThread
22+
[-]NOTE: user needs to enter their username on the commandline first
23+
[-]Remove colored text due to it's being shell-specific

Server.py

100644100755
Lines changed: 89 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
1+
#!/usr/bin/python3
12
import socket
23
import sys
34
import threading
45
import time
6+
import signal
7+
from cryptography.fernet import Fernet
58
i=0
69
class userThread(threading.Thread):
710
def __init__(self,host,portNumber,maxUsersCount):
8-
self.host=host
9-
self.maxUsersCount=maxUsersCount
10-
self.total_user=0
11-
self.connecting_users=[]#keep track of connecting users
12-
self.portNumber=portNumber
13-
self.threads=[]#list of socket thread
14-
self.users=[]#list of usernames of the connected clients
15-
self.sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
16-
self.sock.bind((host,portNumber))
11+
self.host=host
12+
self.maxUsersCount=maxUsersCount
13+
self.total_user=0
14+
self.connecting_users=[]#keep track of connecting users
15+
self.portNumber=portNumber
16+
self.threads=[]#list of socket thread
17+
self.users=[]#list of usernames of the connected clients
18+
self.sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
19+
self.sock.bind((host,portNumber))
20+
self.shared_key=b'gWEdcvtXUknmH8li0G_Aj0DrtJPyrg9SP38_zG-0o10='
21+
self.f=Fernet(self.shared_key)
1722
def run(self):
1823
self.sock.listen(5)
1924
try:
@@ -22,86 +27,100 @@ def run(self):
2227
#if maximum number of connection reached, send back the #busy status
2328
#to the client and close its connection
2429
if self.total_user==self.maxUsersCount:
25-
usrsock.send("#busy")
30+
token=self.f.encrypt(b"#busy")
31+
usrsock.send(token)
2632
usrsock.close()
2733
else:
28-
usrsock.send("#notbusy")
34+
token=self.f.encrypt(b"#notbusy")
35+
usrsock.send(token)
2936
self.threads.append(usrsock)
3037
self.total_user+=1
31-
print "Current user count=",self.total_user
38+
print("Current user count=",self.total_user)
3239
threading.Thread(target=self.thread_handler,args=(usrsock,)).start()
33-
self.sock.close()
40+
self.sock.close()
3441
except socket.error as err:
35-
print err
42+
print(err)
3643
sys.exit()
37-
#handle protocol messages and send broadcast messages
38-
def thread_handler(self,usrsock):
39-
while True:
40-
try:
41-
resp=usrsock.recv(1024)#receiving data
42-
if resp.startswith('#join'):
43-
usr=resp.replace('#join','').lstrip()
44-
if usr in self.users:
45-
global i
46-
usr=usr+str(i)
47-
usrsock.send("#usernametaken %s"%usr)
48-
i+=1
49-
self.broadcast("#newuser %s"%usr,usrsock)
50-
self.users.append(usr)
51-
usrsock.send("#welcome %s"%usr)
52-
#in order to prevent this thread to send 2 packets at the same time
53-
#let it sleep for 1 sec so data can arrive in sequence, not at the same time
54-
time.sleep(1)
55-
print "Current connecting users:"
56-
for usr in self.users:
57-
print usr
58-
if len(self.users)>1:
59-
for i in range(0,len(self.users)):
60-
usrsock.send("#prevjoined %s"%self.users[i])
61-
#announce to all the clients that a new user has joined
62-
if resp.startswith('#status'):
63-
usrsock.send("#statusPosted")
64-
status=resp.replace('#status','').lstrip()
65-
#broadcast status to all other users
66-
self.Ibroadcast("#newStatus %s:%s"%(usr,status))
67-
if resp.startswith('#Bye'):
68-
self.broadcast("#Leave %s"%usr,usrsock)
69-
#broadcast message to all other users saying that a user is leaving
70-
usrsock.send("#Bye")
71-
self.threads.remove(usrsock)#remove that user thread
72-
self.total_user-=1 #subtract 1 from total user
73-
self.users.remove(usr)#remove username from list
74-
print "Current user count=",self.total_user
75-
self.usr=""#set username to empty
76-
usrsock.close()
77-
break
78-
except IOError as err:
79-
print err
80-
sys.exit()
44+
45+
def thread_handler(self,usrsock):
46+
while True:
47+
try:
48+
resp=self.f.decrypt(usrsock.recv(1024)).decode()#receiving data
49+
if resp.startswith('#join'):
50+
usr=resp.replace('#join','').lstrip()
51+
if usr in self.users:
52+
global i
53+
usr=usr+str(i)
54+
token=self.f.encrypt(("#usernametaken %s"%usr).encode())
55+
usrsock.send(token)
56+
i+=1
57+
self.broadcast("#newuser %s"%usr,usrsock)
58+
self.users.append(usr)
59+
token=self.f.encrypt(("#welcome %s"%usr).encode())
60+
usrsock.send(token)
61+
#in order to prevent this thread to send 2 packets at the same time
62+
#let it sleep for 1 sec so data can arrive in sequence, not at the same time
63+
time.sleep(1)
64+
print("Current connecting users:")
65+
for usr in self.users:
66+
print(usr)
67+
if len(self.users)>1:
68+
for i in range(0,len(self.users)):
69+
if self.users[i]!=usr:
70+
token=self.f.encrypt(("#prevjoined %s"%self.users[i]).encode())
71+
usrsock.send(token)
72+
#announce to all the clients that a new user has joined
73+
if resp.startswith('#status'):
74+
token=self.f.encrypt("#statusPosted".encode())
75+
usrsock.send(token)
76+
status=resp.replace('#status','').lstrip()
77+
#broadcast status to all other users
78+
self.broadcast("#newStatus %s:%s"%(usr,status),usrsock)#changed from Ibroadcast, work but doesn't look good, lets try gui!
79+
if resp.startswith('#Bye'):
80+
self.broadcast("#Leave %s"%usr,usrsock)
81+
#broadcast message to all other users saying that a user is leaving
82+
token=self.f.encrypt("#Bye".encode())
83+
usrsock.send(token)
84+
self.threads.remove(usrsock)#remove that user thread
85+
self.total_user-=1 #subtract 1 from total user
86+
self.users.remove(usr)#remove username from list
87+
print("Current user count=",self.total_user)
88+
self.usr=""#set username to empty
89+
usrsock.close()
90+
break
91+
except IOError as err:
92+
print(err)
93+
sys.exit()
8194
#broadcast messages to all clients except the connecting one
82-
def broadcast(self,message,sock):
83-
for thread in self.threads:
84-
if thread!=sock:
85-
thread.send(message)
86-
def Ibroadcast(self,message):
87-
for thread in self.threads:
88-
thread.send(message)
95+
def broadcast(self,message,sock):
96+
for thread in self.threads:
97+
if thread!=sock:
98+
token=self.f.encrypt(message.encode())
99+
thread.send(token)
100+
101+
def Ibroadcast(self,message):
102+
for thread in self.threads:
103+
token=self.f.encrypt(message.encode())
104+
thread.send(token)
89105

106+
# def sig_handler(sig, frame):
107+
# print("Interrupt received, closing program and terminating all connections...")
108+
# sys.exit(1)
90109
def main():
91110
maxUsersCount=5
92111
portNumber=58888
93112
if len(sys.argv)<3:
94-
print "Usage: python Server.py <portNumber> <max user count>"
95-
print "Now using port number=",portNumber
96-
print "Maximum user count=",maxUsersCount
113+
print("Usage: python Server.py <portNumber> <max user count>")
114+
print("Now using port number=",portNumber)
115+
print("Maximum user count=",maxUsersCount)
97116
else:
98117
portNumber=int(sys.argv[1])
99118
maxUsersCount=int(sys.argv[2])
100-
print "Server now using port number=%d\nMaximum user count=%d"%(portNumber,maxUsersCount)
119+
print("Server now using port number=%d\nMaximum user count=%d"%(portNumber,maxUsersCount))
101120
try:
102121
threads=userThread('',portNumber,maxUsersCount).run()#start the work
103122
except IOError as err:
104-
print err
123+
print(err)
105124
sys.exit()
106125
if __name__=='__main__':
107126
main()

0 commit comments

Comments
 (0)