基于python socket、pyqt5 实现的界面化实时通信(仿QQ)

前段时间学了socket编程,也跟着几位up主学了简易的聊天程序,觉得能实现有界面的聊天程序,便利用界面化设计编写了此程序。
利用python socket实现不同主机间的通信,通过服务器转发将不同主机间的通信信息传送,达到一对一通信和多主机建共同通信。再利用pyqt5做出界面,将获得的信息在界面中打印实现。


文章目录

  • 界面实现
  • 主页面
  • 聊天界面
  • socket 通信
  • 服务器端
  • 客户端
  • 截图展示


界面实现

主页面

python3 devtools通讯 python做通讯软件_socket


代码实现:

class MainClass(QMainWindow):
    def __init__(self):
        super(MainClass,self).__init__()
        self.initUI()
        
    def initUI(self):
        self.setWindowTitle("QQ")
        self.setGeometry(1200,100,400,800)
        self.setWindowIcon(QIcon("./img/QQ.png"))

        self.myframe = QFrame(self)
        self.myframe.resize(400,200)
        self.myframe.setStyleSheet("background-color: white;")
        self.picturelb = QLabel("图片",self)
        self.picturelb.resize(100,100)
        self.picturelb.move(50,50)
        self.picturelb.setPixmap(QPixmap("./img/QQ.png"))
        # 照片自适应
        self.picturelb.setScaledContents(True)
        self.namelb = QLabel("账号", self)
        self.namelb.move(180,120)

        chatbtn = QPushButton("好友", self)
        chatbtn.move(0, 200)
        chatbtn.resize(200, 30)
        addbtn = QPushButton("添加", self)
        addbtn.resize(200, 50)
        addbtn.move(0, 750)
        addbtn.clicked.connect(self.AddpersonAct)

        self.tree = QTreeWidget(self)
        self.tree.setHeaderLabel("我的好友")
        # self.tree.setColumnCount(2) 创建列数
        # 宽度
        self.tree.setColumnWidth(0,350)
        self.tree.setHeaderHidden(True)
        self.tree.resize(400,530)
        self.tree.move(0,230)
        self.root1 = QTreeWidgetItem(self.tree)
        self.root1.setText(0,"优秀的人")
        self.root1.setIcon(0, QIcon("./img/QQ.png"))
        self.chat_list.append(self.root1.text(0))

        # 添加子节点
        child1 = QTreeWidgetItem(self.root1)
        child1.setText(0,"测试0")
        child1.setIcon(0,QIcon("./img/QQ.png"))
        child12 = QTreeWidgetItem(self.root1)
        child12.setText(0, "测试1")
        child12.setIcon(0, QIcon("./img/QQ.png"))
        child12 = QTreeWidgetItem(self.root1)
        child12.setText(0, "测试2")
        child12.setIcon(0, QIcon("./img/QQ.png"))

        self.root2 = QTreeWidgetItem(self.tree)
        self.root2.setText(0,"test0")
        self.root2.setIcon(0,QIcon("./img/QQ.png"))
        child21 = QTreeWidgetItem(self.root2)
        child21.setText(0,"test1")
        child21.setIcon(0, QIcon("./img/QQ.png"))
        child22 = QTreeWidgetItem(self.root2)
        child22.setText(0, "test2")
        child22.setIcon(0, QIcon("./img/QQ.png"))
        self.chat_list.append(self.root2.text(0))

        self.root3 = QTreeWidgetItem(self.tree)
        self.root3.setText(0, "群聊")
        self.root3.setIcon(0, QIcon("./img/QQ.png"))
        self.chat_list.append(self.root3.text(0))
        child31 = QTreeWidgetItem(self.root3)
        child31.setText(0, "三人帮")
        child31.setIcon(0, QIcon("./img/QQ.png"))
        self.chat_list.append(self.root3.text(0))
        child32 = QTreeWidgetItem(self.root3)
        child32.setText(0, "跳蚤市场")
        child32.setIcon(0, QIcon("./img/QQ.png"))
		 # 最大最小化、关闭按钮
        self.setWindowFlags(Qt.WindowMinimizeButtonHint|Qt.WindowMaximizeButtonHint|Qt.WindowCloseButtonHint)
        self.show()

聊天界面

代码实现:

class Client(QWidget):
    # 初始化
    def __init__(self):
        super(QWidget, self).__init__()
        # 窗口大小
        self.setGeometry(600,300, 360, 360)
        # 标题
        self.setWindowTitle("聊天")
        self.setWindowIcon(QIcon("./img/QQ.png"))
        
        self.add_ui()
        self.show()

    # 设置组件
    def add_ui(self):
        # 文本框
        self.content = QTextBrowser(self)
        self.content.setGeometry(30,30,300,200)

        # 单行文本
        self.message = QLineEdit(self)
        self.message.setPlaceholderText(u'请输入内容')
        self.message.setGeometry(30, 250, 300, 30)

        # 按钮
        self.button = QPushButton('发送', self)
        self.button.setFont(QFont('微软雅黑', 10, QFont.Bold))
        self.button.setGeometry(270, 300, 60, 30)


        self.button1 = QPushButton('关闭', self)
        self.button1.setFont(QFont('微软雅黑', 10, QFont.Bold))
        self.button1.setGeometry(190, 300, 60, 30)
        self.button1.clicked.connect(self.app_close)

截图展示:

python3 devtools通讯 python做通讯软件_d3_02

socket 通信

所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口

服务器端

代码实现:

class Server:
    # 初始化
    def __init__(self):
        self.server = socket.socket()
        self.server.bind(('127.0.0.1',8888))
        self.server.listen(5)
        print('等待连接:')
        # 所有的客户端
        self.clients = []
        # 绑定用户名字和用户IP
        self.clients_name_ip = {}
        self.get_conn()

    def get_conn(self):
        while True:
            # 获取连接客户端的信息
            client, address = self.server.accept()
            print(client)
            print(address)
            # 打印在界面的聊天界面中
            data = '与服务器连接成功,请输入昵称'
            #
            client.send(data.encode())
            # 连接的用户添加到到列表中
            self.clients.append(client)
            Thread(target=self.get_msg, args=(client, self.clients, self.clients_name_ip, address)).start()


    # 所有客户端的消息处理
    def get_msg(self, client, clients, clients_name_ip, address):
        # 接收客户端发来的昵称
        name = client.recv(1024).decode()
        print('from ', address, name)
        # 昵称和IP进行绑定
        clients_name_ip[address] = name
        # 循环监听消息
        while True:
            # 获取客户发送的消息
            try:
                recv_data = client.recv(1024).decode()
            except Exception as e:
                self.close_client(client, address)
                break
            # 如果用户退出
            if recv_data.upper() == 'Q':
                self.close_client(client, address)
                break
            for c in clients:
                if c == client:
                    c.send(('我说 '+ ' ' + time.strftime('%X') + '\n' + recv_data).encode())
                else:
                    # 在什么时候发送消息     %x 年月日 %X 时分秒
                    c.send((clients_name_ip[address] + ' ' + time.strftime('%X') + '\n' + recv_data).encode())


    def close_client(self, client, address):
        self.clients.remove(client)
        client.close()
        if str(self.clients_name_ip[address]) != 'Q':
            print(self.clients_name_ip[address] + '离开')
            for c in self.clients:
                c.send((self.clients_name_ip[address] + '离开').encode())
                del self.clients_name_ip[address]
        else:
            print('未进入聊天! ')

if __name__ == '__main__':
    Server()

客户端

代码实现:

class Client(QWidget):
    # 初始化
    def __init__(self):
        QWidget.__init__(self)
        # 窗口大小
        self.setGeometry(600,300, 360, 360)
        # 标题
        self.setWindowTitle('聊天室')
        # 添加背景
        # palette = QtGui.QPalette()
        # bg = QtGui.QPixmap(r'./img/xxx.jpg')
        # palette.setBrush(self.backgroundRole(),QtGui.QBrush(bg))
        # self.setPalette(palette)
        #
        self.add_ui()
        self.client = socket.socket()
        self.client.connect(('127.0.0.1',8888))
        self.work_thread()

    # 设置组件
    def add_ui(self):
        # 文本框
        self.content = QTextBrowser(self)
        self.content.setGeometry(30,30,300,200)

        # 单行文本
        self.message = QLineEdit(self)
        self.message.setPlaceholderText(u'请输入内容')
        self.message.setGeometry(30, 250, 300, 30)

        # 按钮
        self.button = QPushButton('发送', self)
        self.button.setFont(QFont('微软雅黑', 10, QFont.Bold))
        self.button.setGeometry(270, 300, 60, 30)


        self.button1 = QPushButton('关闭', self)
        self.button1.setFont(QFont('微软雅黑', 10, QFont.Bold))
        self.button1.setGeometry(190, 300, 60, 30)
        self.button1.clicked.connect(self.app_close)

    def send_msg(self):
        msg = self.message.text()
        self.client.send(msg.encode())
        if msg.upper() == 'Q':
            self.client.close()
            self.destroy()
            app.quit()
        self.message.clear()


    def recv_msg(self):
        while True:
            try:
                data = self.client.recv(1024).decode()
                print(data)
                data = data + '\n'
                self.content.append(data)
            except:
                exit()


    def btn_send(self):
        self.button.clicked.connect(self.send_msg)


    def app_close(self):
        message = 'Q'
        self.client.send(message.encode())
        self.client.close()
        app.quit()

	# 启动多线程实现全双工通信
    def work_thread(self):
        Thread(target=self.btn_send).start()
        Thread(target=self.recv_msg).start()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    client = Client()
    client.show()
    sys.exit(app.exec())

这简易的聊天代码是从其他UP主学习来的,在此基础上进行修改,实现了比之前更多的功能。但是都是比较浅显的功能,特别的基础,但是对于小白的我来说,实属不易,历时几天的修修改改,有了这样的结果。此次经历让我获益匪浅。再附上几张测试图

截图展示

python3 devtools通讯 python做通讯软件_d3_03


python3 devtools通讯 python做通讯软件_pyQt5_04