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

通过Socket实现GUI向控制器传值时出现连接崩溃问题求助

问题分析与解决方案

核心问题点

  • GUI客户端缺失Socket连接初始化代码,client_socket未定义就调用send,实际运行时会先报错;修正后仍存在通信逻辑冗余问题
  • 服务端每次循环重复打开/关闭SPI设备,频繁操作易引发资源占用冲突
  • Socket通信采用二进制字符串转UTF-8传输,额外增加解析成本,且recv(24)依赖固定长度,易出现数据截断或不匹配
  • 双方均无异常处理机制,一旦出现数据传输或SPI操作错误,直接导致连接崩溃

修正后的GUI客户端代码

import math
import struct
import socket
from tkinter import Tk, Frame, Scale, DoubleVar
from tkinter import ttk

Vmax = 10  # 补充缺失的Vmax定义

def Configure(e):
    dacCommand(0, 0, ch0, 0, 0, 0, 1)  # 修正函数名(原Command应为dacCommand)

def dacCommand(bus, dev, dacVar, command, dacGroup, dacChannel, multFac):
    Vref = 3
    offsetCode = 0x1555
    M = 65535
    C = 32768
    Iout = dacVar.get()
    Vout = Iout * multFac

    byte1 = command | dacGroup | dacChannel
    dacCode = math.ceil(Vout * (2**16) / (4 * Vref) + 4 * offsetCode)
    inputCode = math.floor((dacCode - C + (2**15)) * (2**16) / (M + 1))

    # 直接打包成字节,无需转二进制字符串
    data_packet = struct.pack('<B H', byte1, inputCode)
    try:
        client_socket.sendall(data_packet)
    except Exception as e:
        print(f"发送失败: {e}")

if __name__ == "__main__":
    # 初始化Socket连接
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        client_socket.connect((socket.gethostname(), 1234))  # 连接服务端
    except Exception as e:
        print(f"连接服务端失败: {e}")
        exit()

    window = Tk()
    window.title('DACs board control')
    window.geometry('1920x900')
   
    tab_control = ttk.Notebook(window)
    tab2 = Frame(tab_control)
    tab_control.add(tab2, text='dev1 control')
    tab_control.pack(expand=1, fill="both")
    
    ch0 = DoubleVar()
    ttk.Label(tab2, text="ch0 (V)", font=("Calibri", 12)).grid(column=0, row=0, padx=10, pady=5)
    ch0Scale = Scale(tab2, from_=0, to=Vmax, resolution=0.05, state="normal",
                     variable=ch0, command=Configure, font='Helvetica 11',
                     length=200, width=15).grid(row=1, column=0, pady=5, padx=10, sticky='w')
    
    window.mainloop()
    # 关闭连接
    client_socket.close()

修正后的控制器服务端代码

import socket
import spidev

if __name__ == "__main__":
    # 初始化SPI设备(仅执行一次)
    spi = spidev.SpiDev()
    try:
        spi.open(0, 0)
        spi.mode = 0b01
        spi.max_speed_hz = 1000000
    except Exception as e:
        print(f"SPI初始化失败: {e}")
        exit()

    # 初始化Socket服务端
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((socket.gethostname(), 1234))
    s.listen(5)
    print("等待客户端连接...")
    
    conn, address = s.accept()
    print(f"已连接客户端: {address}")
    
    try:
        while True:
            # 接收固定3字节数据(对应客户端发送的1字节byte1 + 2字节inputCode)
            data = conn.recv(3)
            if not data:
                print("客户端断开连接")
                break
            if len(data) != 3:
                print(f"数据长度异常,收到{len(data)}字节,预期3字节")
                continue
            
            # 解析数据
            byte1 = data[0]
            inputCode = int.from_bytes(data[1:3], byteorder='little')
            byte2 = (inputCode >> 8) & 0xFF
            byte3 = inputCode & 0xFF
            
            # 执行SPI传输
            try:
                spi.xfer2([byte1, byte2, byte3])
            except Exception as e:
                print(f"SPI传输失败: {e}")
    except Exception as e:
        print(f"通信异常: {e}")
    finally:
        # 关闭资源
        conn.close()
        spi.close()
        s.close()

关键优化说明

  • Socket通信优化:放弃二进制字符串转UTF-8的传输方式,直接发送结构化字节数据,减少解析错误,提升传输效率
  • SPI资源管理:将SPI初始化移到循环外,避免频繁打开/关闭设备引发的资源冲突
  • 异常处理:添加Socket连接、数据发送/接收、SPI操作的异常捕获,避免程序直接崩溃
  • 客户端初始化:补充Socket连接代码,修复client_socket未定义的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 00:47:50