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

光伏追踪器Python脚本:解决Socket.accept()阻塞主循环的遥测方案

解决方案:解决Socket阻塞主循环的问题

针对你的光伏追踪器Socket遥测方案中accept()阻塞主循环的问题,有三种实用方案,按新手友好度排序:

1. 多线程方案(最适合新手,实现简单)

多线程完全可行,根本不算小题大做——它能让Socket监听在后台线程运行,主线程不受干扰地执行追踪器核心逻辑。只需把Socket服务封装成独立函数,用threading模块启动后台线程即可。

示例代码

import socket
import threading
import time

# 共享遥测数据,写入时加锁保证线程安全(仅读取无需锁)
telemetry_data = {"current_azimuth": 0, "wind_speed": 0.0}
data_lock = threading.Lock()

def run_socket_server():
    # 初始化Socket
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind(('0.0.0.0', 12345))  # 绑定本地端口,OpenVPN内可访问
    server_socket.listen(5)
    
    while True:
        conn, addr = server_socket.accept()
        # 读取最新遥测数据(加锁避免写入冲突)
        with data_lock:
            response = f"Azimuth: {telemetry_data['current_azimuth']}°, Wind Speed: {telemetry_data['wind_speed']} m/s"
        conn.send(response.encode())
        conn.close()

# 启动Socket服务线程(daemon=True表示随主线程退出而终止)
socket_thread = threading.Thread(target=run_socket_server, daemon=True)
socket_thread.start()

# 追踪器主循环
try:
    while True:
        # 模拟追踪器核心逻辑:读取传感器、控制电机等
        # 更新遥测数据时加锁
        with data_lock:
            telemetry_data["current_azimuth"] += 1  # 示例:模拟朝向变化
            telemetry_data["wind_speed"] = 2.5 + (telemetry_data["current_azimuth"] % 5) / 10  # 模拟风速
        
        print(f"Running tracker, current azimuth: {telemetry_data['current_azimuth']}°")
        time.sleep(1)  # 模拟主循环周期
except KeyboardInterrupt:
    print("Shutting down...")

2. 异步IO方案(单线程非阻塞)

如果不想用线程,可以用Python内置的asyncio实现异步Socket服务,主循环和Socket监听在同一个线程内交替执行,无需线程切换。需要把主逻辑改成异步模式(用await替代阻塞操作)。

示例代码

import asyncio

telemetry_data = {"current_azimuth": 0, "wind_speed": 0.0}

async def handle_client(reader, writer):
    # 生成遥测响应
    response = f"Azimuth: {telemetry_data['current_azimuth']}°, Wind Speed: {telemetry_data['wind_speed']} m/s"
    writer.write(response.encode())
    await writer.drain()
    writer.close()
    await writer.wait_closed()

async def socket_server():
    server = await asyncio.start_server(handle_client, '0.0.0.0', 12345)
    async with server:
        await server.serve_forever()

async def tracker_main_loop():
    while True:
        # 异步版追踪器核心逻辑
        telemetry_data["current_azimuth"] += 1
        telemetry_data["wind_speed"] = 2.5 + (telemetry_data["current_azimuth"] % 5) / 10
        
        print(f"Running tracker, current azimuth: {telemetry_data['current_azimuth']}°")
        await asyncio.sleep(1)  # 非阻塞延迟

async def main():
    # 同时运行Socket服务和主循环
    await asyncio.gather(socket_server(), tracker_main_loop())

if __name__ == "__main__":
    asyncio.run(main())

3. 非阻塞Socket+Select方案(嵌入现有主循环)

如果不想改动现有主循环结构,可以把Socket设置为非阻塞模式,用select模块检测连接请求,这样主循环不会被accept()阻塞。

示例代码

import socket
import select
import time

# 初始化非阻塞Socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 12345))
server_socket.listen(5)
server_socket.setblocking(False)  # 关键:设置为非阻塞

telemetry_data = {"current_azimuth": 0, "wind_speed": 0.0}

try:
    while True:
        # 用select检测Socket是否有新连接(超时0.1秒,不阻塞主循环)
        readable, _, _ = select.select([server_socket], [], [], 0.1)
        
        for sock in readable:
            if sock is server_socket:
                conn, addr = server_socket.accept()
                response = f"Azimuth: {telemetry_data['current_azimuth']}°, Wind Speed: {telemetry_data['wind_speed']} m/s"
                conn.send(response.encode())
                conn.close()
        
        # 追踪器主逻辑(和你原有代码完全兼容)
        telemetry_data["current_azimuth"] += 1
        telemetry_data["wind_speed"] = 2.5 + (telemetry_data["current_azimuth"] % 5) / 10
        
        print(f"Running tracker, current azimuth: {telemetry_data['current_azimuth']}°")
        time.sleep(1)
except KeyboardInterrupt:
    server_socket.close()
    print("Shutting down...")

方案对比

  • 多线程:新手友好,逻辑清晰,只需少量改动现有代码。注意遥测数据写入时加锁即可避免线程安全问题。
  • 异步IO:单线程无锁,适合熟悉协程的开发者,需将主循环改为异步模式。
  • 非阻塞Socket+Select:完全兼容现有主循环结构,无需额外线程/协程,代码稍复杂但对原有逻辑侵入性最低。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 20:18:20