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(负责与客户端进行交互,存储聊天对象列表,返回请求)
import socketserver,json,time
import subprocess
connLst = []
groupLst = []
## 代号 地址和端口 连接对象
#optype = {'ag':'group adding','cp':'chat with individual','cg':'chat with group'
class Connector(object): ##连接对象类
def __init__(self,account,password,addrPort,conObj):
self.account = account
self.password = password
self.addrPort = addrPort
self.conObj = conObj
class Group(object):#群组类
def __init__(self,groupname,groupOwner):
self.groupId = 'group'+str(len(groupLst)+1)
self.groupName = 'group'+groupname
self.groupOwner = groupOwner
self.createTime = time.time()
self.members=[groupOwner]
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
print("got connection from",self.client_address)
userIn = False
global connLst
global groupLst
while not userIn:
conn = self.request
data = conn.recv(1024)
if not data:
continue
dataobj = json.loads(data.decode('utf-8'))
#如果连接客户端发送过来的信息格式是一个列表且注册标识为False时进行用户注册或者登陆
ret = '0'
if type(dataobj) == list and not userIn:
account = dataobj[0]
password = dataobj[1]
optype = dataobj[2]
existuser = False
if len(connLst) > 0:
for obj in connLst:
if obj.account == account:
existuser = True
if obj.password == password:
userIn = True
print('{} has logged in system({})'.format(account,self.client_address))
break
if optype == 'login' and (not userIn or not existuser):
ret = '1'
print('{} failed to logged in system({})'.format(account, self.client_address))
else:
if existuser:
ret = '1'
print('{} failed to register({}),account existed!'.format(account, self.client_address))
else:
try:
conObj = Connector(account,password,self.client_address,self.request)
connLst.append(conObj)
print('{} has registered to system({})'.format(account,self.client_address))
userIn = True
except:
print('%s failed to register for exception!'%account)
ret = '99'
#conn.sendall(ret.encode('utf-8'))
if ret == '0':
break
while True:
#除登陆注册之外的请求的监听
conn = self.request
data = conn.recv(1024)
if not data:
continue
print(data)
dataobj = data.decode('utf-8')
dataobj = json.loads(dataobj)
if dataobj['type'] == 'ag' and userIn:
#如果判断用户操作请求类型为添加群组则进行以下操作
groupName = dataobj['groupName']
groupObj = Group(groupName,self.request)
groupLst.append(groupObj)
conn.sendall('ag0'.encode('utf-8'))
print('%s added'%groupName)
continue
if dataobj['type'] == 'eg' and userIn:
#入群操作
groupName = dataobj['groupName']
ret = 'eg1'
for group in groupLst:
if groupName == group.groupName:
group.members.append(self.request)
print('{} added into {}'.format(self.client_address,groupName))
ret = 'eg0'
break
conn.sendall(ret.encode('utf-8'))
continue
#客户端将数据发给服务器端然后由服务器转发给目标客户端
print('connLst',connLst)
print('grouplst',groupLst)
if len(connLst) > 1:
sendok = False
if dataobj['type'] == 'cg':
#群内广播(除发消息的人)
print('group',data)
for obj in groupLst:
if obj.groupName == dataobj['to']:
for user in obj.members:
if user != self.request:
user.sendall(data)
if dataobj['type'] == 'cp':
#个人信息发送
for obj in connLst:
if dataobj['to'] == obj.account:
obj.conObj.sendall(data)
sendok = True
if sendok == False:
print('no target valid!')
if dataobj['type'] == 'f':
for obj in connLst:
if dataobj['to'] == obj.account:
obj.conObj.sendall(data)
sendok = True
if sendok == False:
print('no target valid!')
else:
conn.sendall('-1'.encode('utf-8'))
continue
if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(('localhost',9998),MyServer)
print('waiting for connection...')
server.serve_forever()
client.py(与前端交互,并从后台 sever 获取数据)
from socket import *
import threading,sys,json,re
from PyQt5.QtCore import*
from PyQt5.QtWidgets import *
#引入json模块主要是为了数据的封装传输,re的话是做一些合法性的验证
HOST = 'localhost'
PORT=9998
BUFSIZE = 1024 ##缓冲区大小 1K
ADDR = (HOST,PORT)
myre = r"^[_a-zA-Z]\w{0,}"
tcpCliSock = socket(AF_INET,SOCK_STREAM)
#创建一个socket连接
userAccount = None
#用户登录标志,也用来记录登录的用户名称
def registerAndSend(list):
#用户注册函数
print("""
Glad to have you a member of us!
""")
accout = list[0]
# if not re.findall(myre, accout):
# print('Account illegal!')
# return None
password1 = str(list[1])
password2 = str(list[2])
if not (password1 and password1.__eq__(password2)):
print("password1: %s" %password1)
print("password2: %s" %password2)
print('Password not illegal!')
return None
try:
global userAccount
userAccount = accout
regInfo = [accout,password1,'register']
datastr = json.dumps(regInfo)
tcpCliSock.send(datastr.encode('utf-8'))
#data = tcpCliSock.recv(BUFSIZE)
data = "1"
data = data.decode('utf-8')
if data == '0':
print('Success to register!')
return True
elif data == '1':
print('Failed to register, account existed!')
return False
else:
print('Failed for exceptions!')
return False
except Exception as e:
print(e)
def loginAndSend(list):
#用户登录函数
print("""
Welcome to login in!
""")
accout = list[0]
if not re.findall(myre, accout):
print('Account illegal!')
return None
password = list[1]
if not password:
print('Password illegal!')
return None
global userAccount
userAccount = accout
loginInfo = [accout, password,'login']
datastr = json.dumps(loginInfo)
tcpCliSock.send(datastr.encode('utf-8'))
data = tcpCliSock.recv(BUFSIZE)
if data == '0':
print('Success to login!')
return True
else:
print('Failed to login in(user not exist or username not match the password)!')
return False
def chat(target,msg):
#进入聊天(群聊和点对点聊天可以选择)
print('{} -> {}: '.format(userAccount,target))
print("I am chating now inside the chat function")
if len(msg) > 0 and not msg in 'qQ':
if 'group' in target:
optype = 'cg'
else:
optype = 'cp'
dataObj = {'type': optype, 'to': target, 'msg': msg, 'froms': userAccount}
datastr = json.dumps(dataObj)
tcpCliSock.send(datastr.encode('utf-8'))
def sendFile(target,file):
print("a file send")
dataObj = {'type': "f", 'to': target, "file":file,'froms': userAccount}
print(dataObj["type"])
datastr = json.dumps(dataObj)
tcpCliSock.send(datastr.encode('utf-8'))
print("a file send")
class inputData(threading.Thread):
message = ""
targe = ""
def setMessage(self,msg):
global message
message = msg
print(message)
return message
def setTarget(self,tgt):
global target
targe = tgt
print(targe)
return targe
def run(self):
global targe,message
print(targe)
print(message)
class getdata(QThread):
#接收数据线程
getDataSignal = pyqtSignal(str)
def run(self):
while True:
data = tcpCliSock.recv(BUFSIZE).decode('utf-8')
dataObj = json.loads(data)
if dataObj['type'] == 'cp':
newStr = str('{} -> : {}'.format(dataObj['froms'], dataObj['msg']))
print(newStr)
self.getDataSignal.emit(newStr)
elif dataObj['type'] == 'f':
print("I got your file ")
前端界面展示:
来源: http://www.bubuko.com/infodetail-2467990.html