python实现的聊天室(二)

    技术2022-07-10  96

    python实现的聊天室(二)

    1、前言

    我在python实现的聊天室(一)一文中实现了一个没有界面的聊天室,所有操作都在CMD命令行下进行,用户体验比较差。所以在这一篇文章中,主要实现一个有界面的聊天室。

    2、需求分析

    我们要实现的分为两部分:

    服务器:负责与用户建立 Socket 连接,并将某个用户发送的消息广播到所有在线的用户。显示用户进入/退出聊天室信息。客户端:可以输入聊天的内容并发送,同时可以显示其他用户的消息记录。

    3、服务端实现

    # -*- coding: gbk -*- from PyQt4.QtGui import * from PyQt4.QtCore import * import sys from PyQt4.QtNetwork import * import locale #QTextCodec.setCodecForTr(QTextCodec.codecForName("utf8")) class TcpClientSocket(QTcpSocket): def __init__(self,parent=None): super(TcpClientSocket,self).__init__(parent) self.connect(self,SIGNAL("readyRead()"),self.dataReceive) self.connect(self,SIGNAL("disconnected()"),self.slotDisconnected) self.length = 0 self.msglist = QByteArray() def dataReceive(self): while self.bytesAvailable() > 0: length = self.bytesAvailable() msg = self.read(length) self.emit(SIGNAL("updateClients(QString,int)"),msg,length) def slotDisconnected(self): pass class Server(QTcpServer): def __init__(self,parent=None,port=0): super(Server,self).__init__(parent) self.listen(QHostAddress.Any,port) self.tcpClientSocketList = [] def incomingConnection(self,socketDescriptor): tcpClientSocket = TcpClientSocket(self) self.connect(tcpClientSocket,SIGNAL("updateClients(QString,int)"),self.updateClients) self.connect(tcpClientSocket,SIGNAL("disconnetcted(int)"),self.slotDisconnected) tcpClientSocket.setSocketDescriptor(socketDescriptor) self.tcpClientSocketList.append(tcpClientSocket) def updateClients(self,msg,length): self.emit(SIGNAL("updateServer(QString,int)"),msg,length) for i in xrange(len(self.tcpClientSocketList)): item = self.tcpClientSocketList[i] length_msg = item.writeData(msg) #length_msg = item.writeData(msg.toUtf8()) #if length_msg != msg.toUtf8().length(): # continue def slotDisconnected(self,descriptor): for i in xrange(len(self.tcpClientSocketList)): item = self.tcpClientSocketList[i] if item.socketDescriptor() == descriptor: self.tcpClientSocketList.remove[i] return return class TcpServer(QDialog): def __init__(self,parent=None,f=None): super(TcpServer,self).__init__(parent) self.setWindowTitle("服务端") vbMain = QVBoxLayout(self) self.ListWidgetContent = QListWidget(self) vbMain.addWidget(self.ListWidgetContent) hb = QHBoxLayout() LabelPort = QLabel(self) LabelPort.setText(self.tr("Port:")) hb.addWidget(LabelPort) LineEditPort = QLineEdit(self) hb.addWidget(LineEditPort) vbMain.addLayout(hb) self.PushButtonCreate = QPushButton(self) self.PushButtonCreate.setText(self.tr("创建聊天室")) vbMain.addWidget(self.PushButtonCreate) self.connect(self.PushButtonCreate,SIGNAL("clicked()"),self.slotCreateServer) self.port = 8010 LineEditPort.setText(QString.number(self.port)) def slotCreateServer(self): server = Server(self,self.port) self.connect(server,SIGNAL("updateServer(QString,int)"),self.updateServer) self.PushButtonCreate.setEnabled(False) def updateServer(self,msg,length): #self.ListWidgetContent.addItem(msg.fromUtf8(msg)) self.ListWidgetContent.addItem(msg) if __name__ == '__main__': app=QApplication(sys.argv) mycode = locale.getpreferredencoding() code = QTextCodec.codecForName(mycode) QTextCodec.setCodecForLocale(code) QTextCodec.setCodecForTr(code) QTextCodec.setCodecForCStrings(code) dialog=TcpServer() dialog.show() app.exec_()

    4、客户端实现

    # -*- coding: gbk -*- from PyQt4.QtGui import * from PyQt4.QtCore import * import sys from PyQt4.QtNetwork import * import locale #QTextCodec.setCodecForTr(QTextCodec.codecForName("utf8")) class TcpClient(QDialog): def __init__(self,parent=None): super(TcpClient,self).__init__(parent) self.setWindowTitle(self.tr("客户端")) self.status = False self.serverIP = QHostAddress() self.port = 8010 self.msglist = QByteArray() vbMain = QVBoxLayout(self) self.ListWidgetContent = QListWidget(self) vbMain.addWidget(self.ListWidgetContent) hb = QHBoxLayout() self.LineEditMessage = QLineEdit(self) hb.addWidget(self.LineEditMessage) self.PushButtonSend = QPushButton(self) self.PushButtonSend.setText(self.tr("发送")) self.PushButtonSend.setEnabled(False) hb.addWidget(self.PushButtonSend) self.connect(self.PushButtonSend,SIGNAL("clicked()"),self.slotSend) hb1 = QHBoxLayout() LabelName = QLabel(self) LabelName.setText(self.tr("用户名:")) self.LineEditUser = QLineEdit(self) hb1.addWidget(LabelName) hb1.addWidget(self.LineEditUser) hb2 = QHBoxLayout() LabelServerIP = QLabel(self) LabelServerIP.setText(self.tr("服务器地址:")) self.LineEditIP = QLineEdit(self) hb2.addWidget(LabelServerIP) hb2.addWidget(self.LineEditIP) hb3 = QHBoxLayout() LabelPort = QLabel(self) LabelPort.setText(self.tr("端口:")) self.LineEditPort = QLineEdit(self) hb3.addWidget(LabelPort) hb3.addWidget(self.LineEditPort) vbMain.addLayout(hb) vbMain.addLayout(hb1) vbMain.addLayout(hb2) vbMain.addLayout(hb3) self.PushButtonLeave = QPushButton(self) self.PushButtonLeave.setText(self.tr("进入聊天室")) vbMain.addWidget(self.PushButtonLeave) self.connect(self.PushButtonLeave,SIGNAL("clicked()"),self.slotEnter) def slotSend(self): msg = self.userName + ":" + self.LineEditMessage.text( #length = self.tcpSocket.writeData(msg.toUtf8()) length = self.tcpSocket.writeData(msg) self.LineEditMessage.clear() #if length != msg.toUtf8().length(): # return def slotEnter(self): if not self.status: ip = self.LineEditIP.text() if not self.serverIP.setAddress(ip): QMessageBox.information(self,self.tr("error"),self.tr("server ip address error!")) return if self.LineEditUser.text() == "": QMessageBox.information(self,self.tr("error"),self.tr("User Name error!")) return self.userName = self.LineEditUser.text() self.tcpSocket = QTcpSocket(self) self.connect(self.tcpSocket,SIGNAL("connected()"),self.slotConnected) self.connect(self.tcpSocket,SIGNAL("disconnected()"),self.slotDisconnected) self.connect(self.tcpSocket,SIGNAL("readyRead()"),self.dataReceived) self.tcpSocket.connectToHost(self.serverIP.toString(),8010) self.status = True else: msg = self.userName + ":" + self.tr("离开聊天室") length = self.tcpSocket.writeData(msg) #length = self.tcpSocket.writeData(msg.toUtf8()) #if length != msg.toUtf8().length(): # return self.tcpSocket.disconnectFromHost() self.status = False def slotConnected(self): self.PushButtonSend.setEnabled(True) self.PushButtonLeave.setText(self.tr("离开聊天室")) msg = self.userName + ":" + self.tr("进入聊天室") #length = self.tcpSocket.writeData(msg.toUtf8()) length = self.tcpSocket.writeData(msg) #if length != msg.toUtf8().length(): # return def slotDisconnected(self): self.PushButtonSend.setEnabled(False) self.PushButtonLeave.setText(self.tr("进入聊天室")) def dataReceived(self): while self.tcpSocket.bytesAvailable() > 0: length = self.tcpSocket.bytesAvailable() msg = QString(self.tcpSocket.read(length)) #msg = msg.fromUtf8(msg) #self.ListWidgetContent.addItem(msg.fromUtf8(msg)) self.ListWidgetContent.addItem(msg) if __name__ == '__main__': app=QApplication(sys.argv) mycode = locale.getpreferredencoding() code = QTextCodec.codecForName(mycode) QTextCodec.setCodecForLocale(code) QTextCodec.setCodecForTr(code) QTextCodec.setCodecForCStrings(code) dialog=TcpClient() dialog.show() app.exec_()

    5、运行效果

    运行时先启动服务端,再运行客户端。服务器启动后创建聊天室。客户端运行后,输入昵称、服务器的IP及port信息,进入聊天室。此时服务端会提示用户进入聊天室。当客户端关闭,表明该用户退出聊天室,服务器会转发该用户退出消息到各个客户端。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TLWfRAnb-1593526750899)(http://odsh9s4s2.bkt.clouddn.com/mypyqtchatserver.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XLahNRDt-1593526750901)(http://odsh9s4s2.bkt.clouddn.com/mypyqtchatclientA.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xB06qmLF-1593526750903)(http://odsh9s4s2.bkt.clouddn.com/mypyqtchatclientB.png)]

    6、参考链接

    因为代码中用到了汉字,所以涉及到编码问题。希望该链接能帮助到你。 http://blog.csdn.net/uselym/article/details/51867056 526750901)] [外链图片转存中…(img-xB06qmLF-1593526750903)]

    6、参考链接

    因为代码中用到了汉字,所以涉及到编码问题。希望该链接能帮助到你。 http://blog.csdn.net/uselym/article/details/51867056

    Processed: 0.012, SQL: 9