You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python Socket Error 10054及本地回显服务器连接保持问题求助

解决Socket连接中断与保持连接的问题

先从你用本地回显服务模拟的问题入手,这个问题解决了,原设备的10054错误也能找到明确的排查方向。

你的模拟服务器核心问题

看你的服务器代码,有三个明显的bug导致连接直接关闭且无法回显:

  1. 用错了Socket对象:你在回显时调用了s.sendall(data),但s是用来监听连接的socket,不是和客户端建立的实时连接socket,应该用connection.sendall(data)来发送回显数据。
  2. 数据处理逻辑搞反了:你写的if not data:才去处理,而recv()返回空字节意味着客户端已经断开连接了,这时候再发送肯定失败;正确逻辑是收到有效数据(if data:)时才回显,收到空字节时再终止循环断开连接。
  3. 循环提前终止:原来的逻辑里处理一次数据就break了,导致连接直接关闭,应该持续循环接收直到客户端主动断开。

修正后的服务器代码:

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 1001)
s.bind(server_address)
s.listen(1)

while True:
    print('waiting for connection')
    connection, client_address = s.accept()
    try:
        print('Connection from %s port %s' % client_address )
        # 持续和客户端交互直到对方断开
        while True:
            data = connection.recv(15)
            print('Received: ' + str(data))
            if data:
                try:
                    # 使用和客户端建立的连接socket回显数据
                    connection.sendall(data)
                    print('Echoed data back successfully')
                except Exception as e:
                    print(f'Echo failed: {e}')
                    break
            else:
                # 收到空字节,说明客户端主动断开
                print('Client disconnected')
                break
    finally:
        connection.close()

你的客户端代码问题

客户端这边也有几个细节错误需要修正:

  1. recv()必须指定缓冲区大小soc.recv()没有参数会直接报错,要改成soc.recv(1024)(1024是缓冲区大小,可根据实际数据长度调整)。
  2. 字节数据要解码成字符串recv()返回的是字节对象,直接和字符串拼接会报错,需要用echo.decode('ascii')转成字符串后再打印。
  3. 代码缩进错误echo = soc.recv()那行缩进不对,会导致语法错误,要调整到try代码块内的正确位置。

修正后的客户端代码:

import socket
address = ('127.0.0.1', 1001)
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ok = soc.connect_ex(address)

try:
    if ok == 0:
        print('Connected to device ' + str(ok))
    else:
        print('Connection failed ' + str(ok))
except Exception as e:
    soc.close()
    print("connection not successful, error returned :", e)

try:
    cmd_to_send = 'AT+SENSOR_IDS\r\n'.encode('ascii')
    bytes_sent = soc.sendall(cmd_to_send)
    if bytes_sent is None:
        print('Command sent successfully')
    else:
        print('AT command failed to be sent')
    
    # 读取回显,指定缓冲区大小
    echo = soc.recv(1024)
    if echo:
        print('received echo: ' + echo.decode('ascii'))
    else:
        print('No echo received, connection might be closed')
    
    soc.close()
except Exception as e:
    try:
        soc.close()
        print(f'AT command or echo reading failed: {e}')
    except Exception as inner_e:
        print(f'Process finished with socket exception: {inner_e}')

回到原设备的10054错误和重连问题

10054错误的可能原因

这个错误表示远程设备(你的以太网设备)主动关闭了连接,结合模拟的问题,大概率是以下情况:

  • 你的命令格式不符合设备要求(比如换行符不对,或者命令本身写错了),设备收到无效命令后直接断开。
  • 你调用soc.recv()时没有指定缓冲区大小,这会触发错误,进而导致连接异常中断。
  • 设备需要特定的握手流程(比如先发送认证命令),你直接发AT命令被设备拒绝并断开连接。

重连时Socket被占用的解决

当连接异常断开后,一定要调用soc.close()释放socket资源,否则socket会处于TIME_WAIT状态,短时间内无法重用。另外可以给socket设置SO_REUSEADDR选项,允许端口快速重用:

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 添加这行,允许重用地址和端口
soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

最后总结几个关键要点

  • 服务器端一定要用和客户端建立的connection socket来收发数据,不要用监听的socket。
  • recv()必须指定缓冲区大小,不能留空。
  • 字节和字符串之间要正确编码解码,避免类型错误。
  • 任何异常场景下都要确保关闭socket,防止资源泄漏。
  • 务必对照设备的协议文档(哪怕不全),确认命令格式、交互流程是否正确。

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

火山引擎 最新活动