pyqt5实现简单的 p2p聊天

Posted maxrumi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pyqt5实现简单的 p2p聊天相关的知识,希望对你有一定的参考价值。

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           

前端界面展示:

技术分享图片

 

以上是关于pyqt5实现简单的 p2p聊天的主要内容,如果未能解决你的问题,请参考以下文章

android webrtc 多人网状P2P视频聊天

java基于P2P的聊天和文件传输实例

c#基于udp实现的p2p语音聊天工具

学习 PyQt5。在我的代码片段中找不到错误 [关闭]

actionscript p2p 聊天 - 如何传输视频

区块链简单实现之p2p网络多节点同步