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

GPS追踪器发送LOAD命令后1分钟出现socket连接被强制关闭问题求助

问题描述

我有若干GPS追踪设备,发送"LOAD"命令后,设备会向服务器发送状态信息,初期一切正常能收到响应,但1分钟后出现错误:

An existing connection was forcibly closed by the remote host

恳请协助解决该问题,以下是我的服务器代码:

import datetime
import socket
import threading

host = "0.0.0.0"
port = 4018
connedcted_devices = set()
output_imei_list = set()

def get_clients(sock, conn):
    _msg = "LOAD"
    message = 'message ' + str(_msg)
    encodedMessage = bytes(message, 'utf-8')
     
    output_imei = conn.recv(1024)
    print(output_imei)

    if output_imei in output_imei_list:
        print("Connection already exists")
    else:
        output_imei_list.add(output_imei)
        # print(output_imei_list)
        connedcted_devices.add(conn)
        print("New connection added to cnn_list")
        conn.sendall(encodedMessage)


def receive_response(conn):
    # counter = 0
    while True:
        # if counter == 50 :
        #     break
        
        # conn.settimeout(60) # Set timeout to 60 seconds
        encodedAckText = conn.recv(1024)
        ackText = encodedAckText.decode('utf-8')
        splitedTextList = ackText.split(",")
        list_len = len(splitedTextList)
        if list_len > 0:
            print(splitedTextList)

        # counter += 1
        # print(counter)  


def main():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.bind((host, port))
        print('socket binded')
        sock.listen()
        print('socket now listening')
        
        while True:
            conn, addr = sock.accept()
            get_clients(sock, conn)
            
            if(len(connedcted_devices) > 0):
                for x in connedcted_devices:
                    threading.Thread(target=receive_response, args=(x,)).start()
         

if __name__ == '__main__':
    main()

问题根源分析

  • 重复创建线程:每次新设备连接时,都会遍历所有已连接设备并启动新的receive_response线程,同一个连接被多个线程同时调用recv(),引发IO冲突,最终导致连接被强制关闭。
  • 未处理连接断开:receive_response的死循环没有处理recv()返回空字节的情况(客户端断开的标志),线程会持续异常操作,触发连接关闭。
  • 无超时机制:注释掉了超时设置,recv()会一直阻塞,可能触发设备端的超时断开逻辑。
  • 拼写错误:connedcted_devices存在拼写错误,可能导致集合操作异常。

修复后的代码

import datetime
import socket
import threading

host = "0.0.0.0"
port = 4018
connected_devices = set()  # 修正拼写错误
output_imei_list = set()

def handle_client(conn):
    # 接收设备IMEI
    output_imei = conn.recv(1024)
    if not output_imei:
        conn.close()
        return
    
    print(f"收到设备IMEI: {output_imei}")

    # 检查设备是否已连接
    if output_imei in output_imei_list:
        print("该设备已存在连接,关闭新连接")
        conn.close()
        return
    else:
        output_imei_list.add(output_imei)
        connected_devices.add(conn)
        print("新设备连接已添加")
        
        # 发送LOAD命令
        message = 'message LOAD'
        encodedMessage = bytes(message, 'utf-8')
        conn.sendall(encodedMessage)
    
    # 持续接收设备响应
    try:
        conn.settimeout(60)  # 恢复60秒超时,匹配设备端逻辑
        while True:
            encodedAckText = conn.recv(1024)
            if not encodedAckText:  # 客户端主动断开
                break
            
            ackText = encodedAckText.decode('utf-8').strip()
            if not ackText:
                continue
            
            splitedTextList = ackText.split(",")
            print(f"设备响应: {splitedTextList}")
    except socket.timeout:
        print(f"设备 {output_imei} 超时无响应,关闭连接")
    except Exception as e:
        print(f"处理设备响应时出错: {e}")
    finally:
        # 清理资源,避免内存泄漏
        if conn in connected_devices:
            connected_devices.remove(conn)
        if output_imei in output_imei_list:
            output_imei_list.remove(output_imei)
        conn.close()
        print(f"设备 {output_imei} 连接已关闭")

def main():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.bind((host, port))
        print('Socket已绑定端口')
        sock.listen()
        print('Socket开始监听')
        
        while True:
            conn, addr = sock.accept()
            print(f"收到来自 {addr} 的新连接")
            # 每个新连接单独启动一个线程,避免重复创建
            threading.Thread(target=handle_client, args=(conn,), daemon=True).start()

if __name__ == '__main__':
    main()

关键修改说明

  • 合并处理逻辑:把get_clients和receive_response合并为handle_client,每个连接仅对应一个处理线程,彻底解决多线程IO冲突问题。
  • 处理连接断开:检测recv()返回空字节的情况,及时清理资源并关闭连接。
  • 恢复超时机制:设置60秒超时,防止线程无限阻塞,同时兼容设备端的超时逻辑。
  • 守护线程设置:启动线程时添加daemon=True,确保主程序退出时所有子线程自动结束。
  • 资源清理:在finally块中统一移除设备集合中的连接和IMEI,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 22:17:34