Python下基于TCP协议异步读取以太网数据的方案咨询
Python异步读取TCP Socket数据方案推荐
你当前使用同步while循环阻塞读取TCP数据,确实不够高效。以下是几种无需手动轮询、能在socket有数据时自动触发读取的异步方案:
方法一:使用标准库asyncio(推荐)
asyncio是Python官方异步I/O框架,基于事件驱动模型,无需手动维护轮询循环,当socket有数据可读时会自动唤醒读取逻辑。
结合你的现有代码修改后的示例:
import asyncio import socket import sys import codecs import binascii import struct import time, datetime import array HOST = "192.24.134.1" # 服务器IP或主机名 PORT = 10943 # 服务器端口 ADDR=(HOST,PORT) ID=43 cmd=2 CMDm=cmdf.cfg(cmd,ID) # 生成待发送的TCP数据包 async def tcp_client(): # 建立异步TCP连接 reader, writer = await asyncio.open_connection(HOST, PORT) # 发送命令包 writer.write(CMDm) await writer.drain() # 异步读取数据:当socket有数据时自动执行,无数据时释放事件循环资源 while True: data = await reader.read(2000) if not data: break # 连接关闭时退出 # 这里添加你的数据处理逻辑 print(f"收到数据: {data}") # 关闭连接 writer.close() await writer.wait_closed() # 启动异步事件循环 asyncio.run(tcp_client())
这里的await reader.read(2000)是非阻塞调用,事件循环会在socket无数据时处理其他任务,有数据时才继续执行读取操作,无需手动轮询。
方法二:使用标准库selectors(底层控制)
selectors基于操作系统I/O多路复用机制(如epoll、kqueue),可以监听socket的可读事件,触发回调函数处理数据,适合需要底层控制的场景。
示例代码:
import selectors import socket import sys import codecs import binascii import struct import time, datetime import array HOST = "192.24.134.1" PORT = 10943 ADDR=(HOST,PORT) ID=43 cmd=2 CMDm=cmdf.cfg(cmd,ID) # 创建系统默认的selector实例 sel = selectors.DefaultSelector() def handle_data(sock, mask): """socket可读时触发的回调函数""" data = sock.recv(2000) if data: # 处理收到的数据 print(f"收到数据: {data}") else: # 连接关闭,取消监听并关闭socket sel.unregister(sock) sock.close() def main(): client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(ADDR) client.setblocking(False) # 设置为非阻塞模式 # 发送命令包 client.send(CMDm) # 注册socket的可读事件,绑定回调函数 sel.register(client, selectors.EVENT_READ, handle_data) # 事件循环:自动监听socket事件,有数据时触发回调 while True: events = sel.select() for key, mask in events: callback = key.data callback(key.fileobj, mask) if __name__ == "__main__": main()
sel.select()会阻塞直到有socket事件发生,无需手动检查socket是否有数据,完全由系统通知触发读取。
方法三:第三方库trio(简洁高效)
trio是现代异步I/O库,API设计更简洁直观,错误处理更友好,适合复杂异步场景。需要先通过pip install trio安装。
示例代码:
import trio import socket import sys import codecs import binascii import struct import time, datetime import array HOST = "192.24.134.1" PORT = 10943 ADDR=(HOST,PORT) ID=43 cmd=2 CMDm=cmdf.cfg(cmd,ID) async def tcp_client(): async with await trio.open_tcp_stream(HOST, PORT) as stream: # 发送命令包 await stream.send_all(CMDm) # 异步读取数据,有数据时自动返回 while True: data = await stream.receive_some(2000) if not data: break # 处理数据 print(f"收到数据: {data}") # 启动trio事件循环 trio.run(tcp_client)
trio的receive_some方法会在socket有数据时立即返回,无数据时释放事件循环资源,无需手动轮询。
内容的提问来源于stack exchange,提问作者Sugandh
相关产品推荐
相关产品推荐

