You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PyQt5 GUI程序中公开TCP Socket的accept()创建的conn对象?

解决方案与修复后的代码

核心问题分析

  1. conn作用域问题:conn是OpenConn方法内的局部变量,外部Stream函数无法访问,需将其保存为MainWindow的实例属性。
  2. 文件读取逻辑错误:f.readlines()会将文件指针移至末尾,后续readline无法读取内容,需先缓存所有行再处理。
  3. 未保存选中的文件名:原代码仅更新了UI输入框,未将文件名存入self.filename,导致传输判断逻辑失效。
  4. 线程选择不当:threading.Timer仅执行一次,不适合循环流数据场景,应使用普通Thread。
  5. PyQt与Tkinter混用:两套GUI框架混用易引发冲突,统一使用PyQt的对话框和消息框。
  6. Socket重复定义:全局与主函数内重复创建Socket实例,需统一管理。

修复后的完整代码

import sys
import socket
import threading as th
from time import sleep
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QFileDialog, QMessageBox
)
from GUI import Ui_MainWindow

TCP_IP = '127.0.0.1'
TCP_PORT = 5005
BUFFER_SIZE = 1024

def Stream():
    while True:
        while main_win.Transmit:
            try:
                with open(main_win.filename, "r", encoding='utf-8') as f:
                    lines = f.readlines()
                    total_lines = len(lines)
                    # 发送未传输的行
                    while main_win.Lastline < total_lines and main_win.Transmit:
                        data = lines[main_win.Lastline]
                        main_win.Lastline += 1
                        # Socket发送需字节类型,编码文本
                        main_win.conn.send(data.encode('utf-8'))
            except FileNotFoundError:
                QMessageBox.critical(main_win.main_win, 'Error', 'Error: Archivo no encontrado')
                main_win.Transmit = False
            except Exception as e:
                QMessageBox.critical(main_win.main_win, 'Error', f'Error de transmisión: {str(e)}')
                main_win.Transmit = False
                main_win.Connected = False
                break
            sleep(main_win.ui.doubleSpinBox.value())

class MainWindow:
    Transmit = False
    Lastline = 0
    filename = ""
    Started = False
    Connected = False

    def __init__(self):
        self.main_win = QMainWindow()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self.main_win)
        # 绑定按钮事件
        self.ui.pushButton.clicked.connect(self.on_pushButton_clicked)
        self.ui.pushButton_2.clicked.connect(self.transmit_clicked)
        self.ui.pushButton_4.clicked.connect(self.OpenConn)
        # 初始化Socket
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.s.bind((TCP_IP, TCP_PORT))
        self.s.listen(1)
        self.conn = None  # 初始化连接对象

    def show(self):
        self.main_win.show()

    def on_pushButton_clicked(self):
        # 使用PyQt文件对话框
        filename, _ = QFileDialog.getOpenFileName(
            self.main_win, "Seleccionar archivo", "/", "Archivos de texto (*.txt);;Todos los archivos (*.*)"
        )
        if filename:
            self.filename = filename
            self.ui.lineEdit.setText(filename)

    def transmit_clicked(self):
        if not self.Connected:
            QMessageBox.critical(self.main_win, 'Error', 'Error: No hay una conexión establecida')
            return
        if self.filename == "":
            QMessageBox.critical(self.main_win, 'Error', 'Error: No ha seleccionado el archivo')
            return
        if not self.Transmit:
            self.Transmit = True
            self.ui.pushButton_2.setText("Detener Streaming de datos")
            if not self.Started:
                # 创建守护线程,程序退出时自动终止
                self.stream_thread = th.Thread(target=Stream, daemon=True)
                self.stream_thread.start()
                self.Started = True
        else:
            self.Transmit = False
            self.ui.pushButton_2.setText("Iniciar Streaming de datos")

    def OpenConn(self):
        # 保存连接对象为实例属性
        self.conn, addr = self.s.accept()
        self.Connected = True
        print(f"Conectado a {addr}")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_win = MainWindow()
    main_win.show()
    sys.exit(app.exec_())

关键修改点说明

  • conn作用域修复:在MainWindow类中添加self.conn属性,OpenConn方法中赋值,Stream函数通过main_win.conn访问连接对象。
  • 文件读取逻辑优化:使用with语句安全操作文件,先读取所有行缓存,再按行发送,避免指针位置问题。
  • 文件名保存:选中文件后将路径存入self.filename,确保传输判断逻辑正常。
  • 线程替换:用threading.Thread替代Timer,设置daemon=True保证程序退出时线程自动结束。
  • GUI框架统一:移除所有Tkinter相关代码,使用PyQt原生的QFileDialog和QMessageBox。
  • Socket管理:将Socket创建移至MainWindow初始化方法,避免重复定义。

内容的提问来源于stack exchange,提问作者jorgeneo560

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 15:01:16