python实现的聊天室(二)

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

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

敲代码的雪糕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值