基於Python socket實現簡易網絡聊天室
在這個周末剛剛寫出來的python桌面應用–網絡聊天室,主要通過pyqt5作為桌面應用框架,socket作為網絡編程的框架,從而實現包括客戶端和服務端的網絡聊天室的GUI應用,希望可以一起學習、一起進步!
應用包括服務端server_ui.py、客戶端client_ui.py兩個python模塊實現,並且在pyqt5的使用過程中都使用QThread多線程應用以及基本的UI頁面佈局。開始之前通過一個動態圖來觀察一下socket服務端、socket客戶端通信的實現效果。
1.socket_ui.py 服務端
1-1. 依賴引用
在socket服務端的實現過程中,除瞭pyqt5相關的UI界面的引用外,還包括time、threading、sys、socket等輔助模塊來一起實現socket服務端的桌面應用程序。
from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * import sys from QCandyUi import CandyWindow # 導入 socket 通訊模塊 import socket # 導入時間管理模塊 import time # 導入多線程模塊 import threading
1-2. 實現過程
在服務端的業務實現上面,我們依然是按照之前的GUI實現方式,采用主線程用來實現頁面佈局,子線程QThread來實現業務邏輯的方式來進行實現的,socket的服務端通信業務都是在子線程ServerThread中編寫的。下面是socket服務端桌面應用實現的全部代碼塊,copy到自己的ide中即可直接啟動使用。
class ServerUI(QWidget): def __init__(self): super(ServerUI, self).__init__() self.init_ui() def init_ui(self): self.setWindowTitle('socket 服務端 公眾號:[Python 集中營]') self.setWindowIcon(QIcon('hi.ico')) self.setFixedSize(500, 300) hbox = QHBoxLayout() hbox_v1 = QVBoxLayout() self.brower = QTextBrowser() self.brower.setFont(QFont('宋體', 8)) self.brower.setReadOnly(True) self.brower.setPlaceholderText('消息展示區域...') self.brower.ensureCursorVisible() hbox_v1.addWidget(self.brower) hbox_v2 = QVBoxLayout() hbox_v2_f1 = QFormLayout() self.ip_label = QLabel() self.ip_label.setText('ip地址 ') self.ip_txt = QLineEdit() self.ip_txt.setPlaceholderText('0.0.0.0') self.port_label = QLabel() self.port_label.setText('端口 ') self.port_txt = QLineEdit() self.port_txt.setPlaceholderText('4444') self.lis_num_label = QLabel() self.lis_num_label.setText('最大監聽個數 ') self.lis_num_txt = QLineEdit() self.lis_num_txt.setPlaceholderText('10') self.close_cli_label = QLabel() self.close_cli_label.setText('客戶端關閉指令 ') self.close_cli_txt = QLineEdit() self.close_cli_txt.setPlaceholderText('exit,客戶端發送相應指令則關閉') hbox_v2_f1.addRow(self.ip_label, self.ip_txt) hbox_v2_f1.addRow(self.port_label, self.port_txt) hbox_v2_f1.addRow(self.lis_num_label, self.lis_num_txt) hbox_v2_f1.addRow(self.close_cli_label, self.close_cli_txt) self.start_btn = QPushButton() self.start_btn.setText('開啟服務端') self.start_btn.clicked.connect(self.start_btn_clk) hbox_v2.addLayout(hbox_v2_f1) hbox_v2.addWidget(self.start_btn) hbox.addLayout(hbox_v1) hbox.addLayout(hbox_v2) self.thread_ = ServerThread(self) self.thread_.message.connect(self.show_message) self.setLayout(hbox) def show_message(self, text): ''' 槽函數:向文本瀏覽器中寫入內容 :param text: :return: ''' cursor = self.brower.textCursor() cursor.movePosition(QTextCursor.End) self.brower.append(text) self.brower.setTextCursor(cursor) self.brower.ensureCursorVisible() def start_btn_clk(self): self.thread_.start() self.start_btn.setEnabled(False) class ServerThread(QThread): message = pyqtSignal(str) def __init__(self, parent=None): super(ServerThread, self).__init__(parent) self.parent = parent self.working = True def __del__(self): self.working = False self.wait() def run(self): self.message.emit('準備啟動socket服務端...') # 創建服務端 socket socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 綁定服務地址、端口 address = (self.parent.ip_txt.text().strip(), int(self.parent.port_txt.text().strip())) socket_server.bind(address) # 設置監聽最大等待數 socket_server.listen(int(self.parent.lis_num_txt.text().strip())) self.message.emit("服務已經啟動,正在等待客戶端連接...") while True: # 設置睡眠時間 time.sleep(0.1) # 允許客戶端連接 client, info = socket_server.accept() self.client, self.info = client, info # 啟用新線程調用消息處理 thread = threading.Thread(target=self.catch_message) # 設置為守護線程 thread.setDaemon(True) # 開啟線程執行 thread.start() def catch_message(self): self.client.send("歡迎來到網絡聊天室".encode('utf-8')) self.message.emit("客戶端信息:" + str(self.info)) close_cli = self.parent.close_cli_txt.text().strip() while True: try: # 接收客戶端消息、接收最大長度為 1024,並進行 utf-8 解碼 message = self.client.recv(1024).decode('utf-8') # 校驗是否關閉客戶端 if not message and close_cli == message: self.client.close() self.message.emit("當前客戶端已關閉!") break self.message.emit("接收到消息:" + message) # 將消息進行 utf-8 編碼後發給客戶端 rcv = "服務端成功接收消息:" + message self.client.send(rcv.encode('utf-8')) except Exception as e: self.client.send("服務端處理消息異常!".encode('utf-8')) break if __name__ == '__main__': app = QApplication(sys.argv) w = CandyWindow.createWindow(ServerUI(), theme='blueGreen', title='socket 服務端 公眾號:[Python 集中營]', ico_path='hi.ico') w.show() sys.exit(app.exec_())
1-3. 實現效果
2.client_ui.py 客戶端
2-1. 依賴引用
在socket客戶端的實現過程中,除瞭pyqt5相關的UI界面的引用外,還包括sys、socket等輔助模塊來一起實現socket服務端的桌面應用程序,相比服務端來說,客戶端並沒有使用多線程threading模塊。
from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * import sys from QCandyUi import CandyWindow # 導入socket 通信模塊 import socket
2-2. 實現過程
客戶端的實現過程和服務端server_ui.py實現是基本相似的,同樣也使用到瞭pyqt5的QThread的子線程應用,唯一不同的是socket客戶端通信方式跟服務端不大相同,同樣將下面的代碼塊copy到自己的ide中直接使用即可。
class ClientUI(QWidget): def __init__(self): super(ClientUI, self).__init__() self.init_ui() def init_ui(self): self.setWindowTitle('socket 客戶端 公眾號:[Python 集中營]') self.setWindowIcon(QIcon('hi.ico')) self.setFixedSize(500, 300) hbox = QHBoxLayout() hbox_v1 = QVBoxLayout() self.brower = QTextBrowser() self.brower.setFont(QFont('宋體', 8)) self.brower.setReadOnly(True) self.brower.setPlaceholderText('消息展示區域...') self.brower.ensureCursorVisible() hbox_v1.addWidget(self.brower) hbox_v2 = QVBoxLayout() hbox_v2_g1 = QGridLayout() self.ip_label = QLabel() self.ip_label.setText('ip地址 ') self.ip_txt = QLineEdit() self.ip_txt.setPlaceholderText('0.0.0.0') self.port_label = QLabel() self.port_label.setText('端口 ') self.port_txt = QLineEdit() self.port_txt.setPlaceholderText('4444') self.message = QTextEdit() self.message.setPlaceholderText('發送消息內容...') hbox_v2_g1.addWidget(self.ip_label, 0, 0, 1, 1) hbox_v2_g1.addWidget(self.ip_txt, 0, 1, 1, 1) hbox_v2_g1.addWidget(self.port_label, 1, 0, 1, 1) hbox_v2_g1.addWidget(self.port_txt, 1, 1, 1, 1) hbox_v2_g1.addWidget(self.message, 2, 0, 1, 2) self.start_btn = QPushButton() self.start_btn.setText('發送消息') self.start_btn.clicked.connect(self.start_btn_clk) hbox_v2.addLayout(hbox_v2_g1) hbox_v2.addWidget(self.start_btn) hbox.addLayout(hbox_v1) hbox.addLayout(hbox_v2) self.thread_ = ClientThread(self) self.thread_.message.connect(self.show_message) self.setLayout(hbox) def show_message(self, text): ''' 槽函數:向文本瀏覽器中寫入內容 :param text: :return: ''' cursor = self.brower.textCursor() cursor.movePosition(QTextCursor.End) self.brower.append(text) self.brower.setTextCursor(cursor) self.brower.ensureCursorVisible() def start_btn_clk(self): self.thread_.start() class ClientThread(QThread): message = pyqtSignal(str) def __init__(self, parent=None): super(ClientThread, self).__init__(parent) self.parent = parent self.working = True self.is_connect = False def __del__(self): self.working = False self.wait() def run(self): try: if self.is_connect is False: self.connect_serv() # 將控制臺輸入消息進行 utf-8 編碼後發送 self.socket_client.send(self.parent.message.toPlainText().strip().encode('utf-8')) self.message.emit(self.socket_client.recv(1024).decode('utf-8')) except Exception as e: self.message.emit("發送消息異常:" + str(e)) def connect_serv(self): try: self.message.emit("正在創建客戶端socket...") # 創建客戶端 socket self.socket_client = socket.socket() # 連接服務端 address = (self.parent.ip_txt.text().strip(), int(self.parent.port_txt.text().strip())) self.socket_client.connect(address) self.message.emit("服務端連接成功...") # 接收服務端消息並進行 utf-8 解碼 self.message.emit(self.socket_client.recv(1024).decode()) self.is_connect = True except: self.is_connect = False if __name__ == '__main__': app = QApplication(sys.argv) w = CandyWindow.createWindow(ClientUI(), theme='blueGreen', title='socket 客戶端 公眾號:[Python 集中營]', ico_path='hi.ico') w.show() sys.exit(app.exec_())
2-3. 實現效果
以上就是基於Python socket實現簡易網絡聊天室的詳細內容,更多關於Python socket網絡聊天室的資料請關註WalkonNet其它相關文章!