UI.py(简单的前端界面实现)
import sys from PyQt5.QtCore import* from PyQt5.QtWidgets import * from newClient import* from PyQt5.QtGui import QIcon #主页 class MainPage(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setGeometry(500, 50, 0, 0) self.setWindowTitle(‘‘) self.setWindowIcon(QIcon(‘icon.jpg‘)) self.resize(300,300) self.loginButton = QPushButton(self) self.loginButton.setText("登陆") #text self.loginButton.setIcon(QIcon("close.png")) #icon self.loginButton.setShortcut(‘Ctrl+D‘) #shortcut key self.loginButton.clicked.connect(self.close) self.loginButton.setToolTip("Login") #Tool tip self.loginButton.move(50,100) self.registerButton = QPushButton(self) self.registerButton.setText("注册") #text self.registerButton.setIcon(QIcon("close.png")) #icon self.registerButton.setShortcut(‘Ctrl+D‘) #shortcut key self.registerButton.clicked.connect(self.close) self.registerButton.setToolTip("Register") #Tool tip self.registerButton.move(150,100) self.show() #跳转到登陆界面 class Login(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setGeometry(500, 50, 0, 0) self.setWindowTitle(‘登陆界面‘) self.setWindowIcon(QIcon(‘icon.jpg‘)) self.resize(400,300) layout = QGridLayout() nameLabel = QLabel("用户名") self.nameLineEdit = QLineEdit(" ") passWordLabel = QLabel("密码") self.passWordLineEdit = QLineEdit(" ") self.confirmButton = QPushButton("确定") self.cancelButton = QPushButton("取消") self.cancelButton.resize(50,50) self.confirmButton.clicked.connect(self.addUser) layout.addWidget(nameLabel,1,0) layout.addWidget(self.nameLineEdit,1,1) layout.addWidget(passWordLabel,2,0) layout.addWidget(self.passWordLineEdit,2,1) layout.addWidget(self.confirmButton) layout.addWidget(self.cancelButton) layout.setColumnStretch(1, 2) self.setLayout(layout) def handle_click(self): if not self.isVisible(): self.show() def addUser(self): pList = [] pList.append(self.nameLineEdit.text) pList.append(self.passWordLineEdit) loginAndSend(pList) #注册界面 class Register(QWidget): registerSignal = pyqtSignal(list) def __init__(self): super().__init__() self.initUI() def bindSignal(self,func): self.registerSignal.connect(func) def initUI(self): self.setGeometry(500, 50, 0, 0) self.setWindowTitle(‘注册界面‘) self.setWindowIcon(QIcon(‘icon.jpg‘)) self.resize(300,300) layout = QGridLayout() nameLabel = QLabel("用户名") self.nameLineEdit = QLineEdit("") passWordLabel1 = QLabel("密码") self.passWordLineEdit1 = QLineEdit("") passWordLabel2 = QLabel("确定密码") self.passWordLineEdit2 = QLineEdit("") ipAddress = QLabel("IP地址") self.ipAddressEdit =QLineEdit("") ipPort = QLabel("端口") self.ipPortEdit = QLineEdit("") self.confirmButton = QPushButton("确定") self.cancelButton = QPushButton("取消") self.cancelButton.resize(50,50) layout.addWidget(nameLabel,1,0) layout.addWidget(self.nameLineEdit,1,1) layout.addWidget(passWordLabel1,2,0) layout.addWidget(self.passWordLineEdit1,2,1) layout.addWidget(passWordLabel2,3,0) layout.addWidget(self.passWordLineEdit2,3,1) layout.addWidget(ipAddress,4,0) layout.addWidget(self.ipAddressEdit,4,1) layout.addWidget(ipPort,5,0) layout.addWidget(self.ipPortEdit,5,1) layout.addWidget(self.confirmButton) layout.addWidget(self.cancelButton) layout.setColumnStretch(1, 3) self.setLayout(layout) def sendData(self): pList =[] pList.append(str(self.nameLineEdit.text())) pList.append(str(self.passWordLineEdit1.text())) pList.append(str(self.passWordLineEdit2.text())) re = registerAndSend(pList) if re: print("注册成功") def handle_click(self): if not self.isVisible(): self.show() class chatPage(QMainWindow): inputSigal = pyqtSignal(str) sendMesSignal = pyqtSignal(str) def __init__(self): super().__init__() self.initUI() def initUI(self): self.setGeometry(800, 50, 0, 0) self.setWindowTitle(‘‘) self.setWindowIcon(QIcon(‘icon.jpg‘)) self.resize(300,600) #设置中心窗口 componudWidget = QWidget() layout = QGridLayout() self.inputText = QTextEdit("输入聊天信息") self.inputText.resize(100,100) self.inputConButton = QPushButton("发送消息") self.inputCanBUtton = QPushButton("取消发送") self.showText = QTextEdit("message is here") self.showText.resize(100,100) layout.addWidget(self.showText) layout.addWidget(self.inputText) layout.addWidget(self.inputConButton) layout.addWidget(self.inputCanBUtton) componudWidget.setLayout(layout) self.setCentralWidget(componudWidget) #创建触发事件 self.exitAction = QAction(QIcon(‘exit.png‘), ‘&Exit‘, self) self.exitAction.setShortcut(‘Ctrl+Q‘) self.exitAction.setStatusTip(‘Exit application‘) self.exitAction.triggered.connect(qApp.quit) self.indivChatA = QAction(QIcon(‘exit.png‘), ‘开始聊天‘, self) self.indivChatA .setShortcut("开始聊天") self.groupChatA = QAction(QIcon(‘exit.png‘), ‘创建一个群聊‘, self) self.groupChatA .setShortcut("创建群聊") self.eGroupChatA = QAction(QIcon(‘exit.png‘), ‘开始加入一个群聊‘, self) self.eGroupChatA .setShortcut("加入群聊") self.aGroupChatA = QAction(QIcon(‘exit.png‘), ‘添加一个群聊‘, self) self.aGroupChatA .setShortcut("添加群聊") self.upFileA = QAction(QIcon(‘exit.png‘), ‘上传文件‘, self) self.upFileA.setShortcut("上传文件") self.getHelpA = QAction(QIcon(‘exit.png‘), ‘帮助‘, self) self.getHelpA.setShortcut("帮助") #添加菜单 self.chat =self.menuBar().addMenu("聊天") self.indivChat = self.chat.addMenu("选择个体聊天") self.groupChat = self.chat.addMenu("创建群聊") self.enterGC = self.chat.addMenu("加入群聊") self.addGC = self.chat.addMenu("添加群聊") self.up = self.menuBar().addMenu("上传文件") self.help = self.menuBar().addMenu("帮助") self.chooseUser = self.menuBar().addMenu("选择聊天对象") self.quit = self.menuBar().addMenu("退出系统") #为菜单添加Action self.indivChat.addAction(self.indivChatA) #添加个体聊天Action self.groupChat.addAction(self.groupChatA) #群聊Action self.enterGC.addAction(self.eGroupChatA) #加入群聊Action self.addGC.addAction(self.aGroupChatA) #添加群聊Action self.up.addAction(self.upFileA) #上传文件Action self.help.addAction(self.getHelpA) #帮助Action #添加信号槽 self.inputConButton.clicked.connect(self.sendMessage) self.inputCanBUtton.clicked.connect(self.sendMessage) self.indivChatA.triggered.connect(lambda:self.emitChatSiganl("cp")) #个体聊天触发事件 self.groupChatA.triggered.connect(lambda:self.emitChatSiganl("cg")) #群聊触发事件 self.eGroupChatA.triggered.connect(lambda:self.emitChatSiganl("eg"))#加入一个群聊 self.aGroupChatA.triggered.connect(lambda:self.emitChatSiganl("ag"))#添加一个群聊 self.upFileA.triggered.connect(self.openFile) #上传文件触发事件 self.getHelpA.triggered.connect(lambda:self.emitChatSiganl("h")) #获取帮助触发事件 self.quit.addAction(self.exitAction) def handle_click(self): self.showText.setText("聊天内容") if not self.isVisible(): self.show() def emitChatSiganl(self,signal): self.inputSigal.emit(signal) print("lunched now") def sendMessage(self): message = str(self.inputText.toPlainText()) target = "max" chat(target,message) print(message) print ("message has emited") def setText(self,message): print(message) self.showText.setText(message) print(message) def openFile(self): fileName, filetype = QFileDialog.getOpenFileName(self, "选择文件路径", "H:/", "All Files (*);;Text Files (*.txt)") print(fileName) target = "max" file = open(fileName) print("文件打开成功") data = file.read(1024) print("文件读取成功") sendFile(target,data) print("文件发送成功") print(fileName) if __name__ == ‘__main__‘: #创建页面实例对象 app = QApplication(sys.argv) mp = MainPage() #主页 lg = Login() #登陆界面 re = Register() #注册界面 cp = chatPage() #聊天界面 myInputData = inputData() # myGetData = getData() mydata = getdata() #将信号绑定到槽 mydata.getDataSignal.connect(cp.setText) cp.inputSigal.connect(myInputData.setTarget) mp.loginButton.clicked.connect(lg.handle_click) mp.loginButton.clicked.connect(mp.hide) mp.registerButton.clicked.connect(re.handle_click) mp.registerButton.clicked.connect(mp.hide) re.confirmButton.clicked.connect(re.sendData) re.confirmButton.clicked.connect(cp.handle_click) lg.cancelButton.clicked.connect(QCoreApplication.quit) cp.sendMesSignal.connect(myInputData.setMessage) #与服务器建立连接,获取链接对象 tcpCliSock.connect(ADDR) print(‘Connected with server‘) mydata.start() sys.exit(app.exec_())
server.py(负责与客户端进行交互,存储聊天对象列表,返回请求)
1 import socketserver,json,time 2 import subprocess 3 4 connLst = [] 5 groupLst = [] 6 ## 代号 地址和端口 连接对象 7 #optype = {‘ag‘:‘group adding‘,‘cp‘:‘chat with individual‘,‘cg‘:‘chat with group‘} 8 class Connector(object): ##连接对象类 9 def __init__(self,account,password,addrPort,conObj): 10 self.account = account 11 self.password = password 12 self.addrPort = addrPort 13 self.conObj = conObj 14 15 class Group(object):#群组类 16 def __init__(self,groupname,groupOwner): 17 self.groupId = ‘group‘+str(len(groupLst)+1) 18 self.groupName = ‘group‘+groupname 19 self.groupOwner = groupOwner 20 self.createTime = time.time() 21 self.members=[groupOwner] 22 23 class MyServer(socketserver.BaseRequestHandler): 24 25 def handle(self): 26 print("got connection from",self.client_address) 27 userIn = False 28 global connLst 29 global groupLst 30 while not userIn: 31 conn = self.request 32 data = conn.recv(1024) 33 if not data: 34 continue 35 dataobj = json.loads(data.decode(‘utf-8‘)) 36 #如果连接客户端发送过来的信息格式是一个列表且注册标识为False时进行用户注册或者登陆 37 ret = ‘0‘ 38 if type(dataobj) == list and not userIn: 39 account = dataobj[0] 40 password = dataobj[1] 41 optype = dataobj[2] 42 existuser = False 43 if len(connLst) > 0: 44 for obj in connLst: 45 if obj.account == account: 46 existuser = True 47 if obj.password == password: 48 userIn = True 49 print(‘{} has logged in system({})‘.format(account,self.client_address)) 50 break 51 if optype == ‘login‘ and (not userIn or not existuser): 52 ret = ‘1‘ 53 print(‘{} failed to logged in system({})‘.format(account, self.client_address)) 54 else: 55 if existuser: 56 ret = ‘1‘ 57 print(‘{} failed to register({}),account existed!‘.format(account, self.client_address)) 58 else: 59 try: 60 conObj = Connector(account,password,self.client_address,self.request) 61 connLst.append(conObj) 62 print(‘{} has registered to system({})‘.format(account,self.client_address)) 63 userIn = True 64 except: 65 print(‘%s failed to register for exception!‘%account) 66 ret = ‘99‘ 67 #conn.sendall(ret.encode(‘utf-8‘)) 68 if ret == ‘0‘: 69 break 70 71 while True: 72 #除登陆注册之外的请求的监听 73 conn = self.request 74 data = conn.recv(1024) 75 if not data: 76 continue 77 print(data) 78 dataobj = data.decode(‘utf-8‘) 79 dataobj = json.loads(dataobj) 80 if dataobj[‘type‘] == ‘ag‘ and userIn: 81 #如果判断用户操作请求类型为添加群组则进行以下操作 82 groupName = dataobj[‘groupName‘] 83 groupObj = Group(groupName,self.request) 84 groupLst.append(groupObj) 85 conn.sendall(‘ag0‘.encode(‘utf-8‘)) 86 print(‘%s added‘%groupName) 87 continue 88 89 if dataobj[‘type‘] == ‘eg‘ and userIn: 90 #入群操作 91 groupName = dataobj[‘groupName‘] 92 ret = ‘eg1‘ 93 for group in groupLst: 94 if groupName == group.groupName: 95 group.members.append(self.request) 96 print(‘{} added into {}‘.format(self.client_address,groupName)) 97 ret = ‘eg0‘ 98 break 99 conn.sendall(ret.encode(‘utf-8‘)) 100 continue 101 102 #客户端将数据发给服务器端然后由服务器转发给目标客户端 103 print(‘connLst‘,connLst) 104 print(‘grouplst‘,groupLst) 105 if len(connLst) > 1: 106 sendok = False 107 if dataobj[‘type‘] == ‘cg‘: 108 #群内广播(除发消息的人) 109 print(‘group‘,data) 110 for obj in groupLst: 111 if obj.groupName == dataobj[‘to‘]: 112 for user in obj.members: 113 if user != self.request: 114 user.sendall(data) 115 if dataobj[‘type‘] == ‘cp‘: 116 #个人信息发送 117 for obj in connLst: 118 if dataobj[‘to‘] == obj.account: 119 obj.conObj.sendall(data) 120 sendok = True 121 if sendok == False: 122 print(‘no target valid!‘) 123 if dataobj[‘type‘] == ‘f‘: 124 for obj in connLst: 125 if dataobj[‘to‘] == obj.account: 126 obj.conObj.sendall(data) 127 sendok = True 128 if sendok == False: 129 print(‘no target valid!‘) 130 else: 131 conn.sendall(‘-1‘.encode(‘utf-8‘)) 132 continue 133 134 if __name__ == ‘__main__‘: 135 server = socketserver.ThreadingTCPServer((‘localhost‘,9998),MyServer) 136 print(‘waiting for connection...‘) 137 server.serve_forever()
client.py(与前端交互,并从后台sever获取数据)
1 from socket import * 2 import threading,sys,json,re 3 from PyQt5.QtCore import* 4 from PyQt5.QtWidgets import * 5 #引入json模块主要是为了数据的封装传输,re的话是做一些合法性的验证 6 HOST = ‘localhost‘ 7 PORT=9998 8 BUFSIZE = 1024 ##缓冲区大小 1K 9 ADDR = (HOST,PORT) 10 myre = r"^[_a-zA-Z]\w{0,}" 11 tcpCliSock = socket(AF_INET,SOCK_STREAM) 12 #创建一个socket连接 13 userAccount = None 14 #用户登录标志,也用来记录登录的用户名称 15 def registerAndSend(list): 16 #用户注册函数 17 print(""" 18 Glad to have you a member of us! 19 """) 20 accout = list[0] 21 # if not re.findall(myre, accout): 22 # print(‘Account illegal!‘) 23 # return None 24 password1 = str(list[1]) 25 password2 = str(list[2]) 26 if not (password1 and password1.__eq__(password2)): 27 print("password1: %s" %password1) 28 print("password2: %s" %password2) 29 print(‘Password not illegal!‘) 30 return None 31 try: 32 global userAccount 33 userAccount = accout 34 regInfo = [accout,password1,‘register‘] 35 datastr = json.dumps(regInfo) 36 tcpCliSock.send(datastr.encode(‘utf-8‘)) 37 #data = tcpCliSock.recv(BUFSIZE) 38 data = "1" 39 data = data.decode(‘utf-8‘) 40 if data == ‘0‘: 41 print(‘Success to register!‘) 42 return True 43 elif data == ‘1‘: 44 print(‘Failed to register, account existed!‘) 45 return False 46 else: 47 print(‘Failed for exceptions!‘) 48 return False 49 except Exception as e: 50 print(e) 51 52 def loginAndSend(list): 53 #用户登录函数 54 print(""" 55 Welcome to login in! 56 """) 57 accout = list[0] 58 if not re.findall(myre, accout): 59 print(‘Account illegal!‘) 60 return None 61 password = list[1] 62 if not password: 63 print(‘Password illegal!‘) 64 return None 65 global userAccount 66 userAccount = accout 67 loginInfo = [accout, password,‘login‘] 68 datastr = json.dumps(loginInfo) 69 tcpCliSock.send(datastr.encode(‘utf-8‘)) 70 data = tcpCliSock.recv(BUFSIZE) 71 if data == ‘0‘: 72 print(‘Success to login!‘) 73 return True 74 else: 75 print(‘Failed to login in(user not exist or username not match the password)!‘) 76 return False 77 78 def chat(target,msg): 79 #进入聊天(群聊和点对点聊天可以选择) 80 print(‘{} -> {}: ‘.format(userAccount,target)) 81 print("I am chating now inside the chat function") 82 if len(msg) > 0 and not msg in ‘qQ‘: 83 if ‘group‘ in target: 84 optype = ‘cg‘ 85 else: 86 optype = ‘cp‘ 87 88 dataObj = {‘type‘: optype, ‘to‘: target, ‘msg‘: msg, ‘froms‘: userAccount} 89 datastr = json.dumps(dataObj) 90 tcpCliSock.send(datastr.encode(‘utf-8‘)) 91 def sendFile(target,file): 92 print("a file send") 93 dataObj = {‘type‘: "f", ‘to‘: target, "file":file,‘froms‘: userAccount} 94 print(dataObj["type"]) 95 datastr = json.dumps(dataObj) 96 tcpCliSock.send(datastr.encode(‘utf-8‘)) 97 print("a file send") 98 99 100 class inputData(threading.Thread): 101 message = "" 102 targe = "" 103 def setMessage(self,msg): 104 global message 105 message = msg 106 print(message) 107 return message 108 def setTarget(self,tgt): 109 global target 110 targe = tgt 111 print(targe) 112 return targe 113 def run(self): 114 global targe,message 115 print(targe) 116 print(message) 117 118 119 class getdata(QThread): 120 #接收数据线程 121 getDataSignal = pyqtSignal(str) 122 def run(self): 123 while True: 124 125 126 data = tcpCliSock.recv(BUFSIZE).decode(‘utf-8‘) 127 dataObj = json.loads(data) 128 if dataObj[‘type‘] == ‘cp‘: 129 newStr = str(‘{} -> : {}‘.format(dataObj[‘froms‘], dataObj[‘msg‘])) 130 print(newStr) 131 self.getDataSignal.emit(newStr) 132 elif dataObj[‘type‘] == ‘f‘: 133 print("I got your file ") 134
前端界面展示: