通过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
相关产品推荐
相关产品推荐

