226 lines
8.2 KiB
Python
226 lines
8.2 KiB
Python
|
|
from queue import Full
|
|||
|
|
import socket
|
|||
|
|
import threading
|
|||
|
|
import time
|
|||
|
|
from typing import Dict, Optional
|
|||
|
|
from loguru import logger
|
|||
|
|
|
|||
|
|
import telnetlib #2026/6/2
|
|||
|
|
|
|||
|
|
# 全局:TCP客户端管理(每个UART一个实例)
|
|||
|
|
tcp_clients: Dict[str, "TCPUARTClient"] = {}
|
|||
|
|
# HEAD = b"\xeb\x90" #地测帧头
|
|||
|
|
# TAIL = b"\x57\x16" #地测帧尾
|
|||
|
|
# MIN_FRAME = 23 ##地测长度最小值
|
|||
|
|
# MAX_FRAME = 1000 ##地测帧长度最大值
|
|||
|
|
|
|||
|
|
class TCPUARTClient:
|
|||
|
|
def __init__(self, dev_name: str, local_port: int, remote_port: int, remote_ip="127.0.0.1"):
|
|||
|
|
self.dev_name = dev_name
|
|||
|
|
self.local_port = local_port
|
|||
|
|
self.remote_port = remote_port
|
|||
|
|
self.remote_ip = remote_ip
|
|||
|
|
self.socket = None
|
|||
|
|
self.running = False
|
|||
|
|
self.thread = None
|
|||
|
|
|
|||
|
|
self.HEAD = b"\xeb\x90" #地测帧头
|
|||
|
|
self.TAIL = b"\x57\x16" #地测帧尾
|
|||
|
|
self.MIN_LEN = 23 ##地测长度最小值
|
|||
|
|
self.MAX_LEN = 1000 ##地测帧长度最大值
|
|||
|
|
self.tcp_buf = b''
|
|||
|
|
|
|||
|
|
#self.tn = None
|
|||
|
|
|
|||
|
|
|
|||
|
|
def connect(self):
|
|||
|
|
try:
|
|||
|
|
|
|||
|
|
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|||
|
|
# 关键点:禁止Nagle算法,模仿网络调试助手,强制使用纯raw socket连接,但是导致TCP收不到数据 2026/6/2
|
|||
|
|
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #停用
|
|||
|
|
#self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) #telnet
|
|||
|
|
self.socket.bind(("127.0.0.1", self.local_port))
|
|||
|
|
self.socket.connect((self.remote_ip, self.remote_port))
|
|||
|
|
self.socket.setblocking(False)
|
|||
|
|
|
|||
|
|
self.running = True
|
|||
|
|
print(f"[TCP-UART] {self.dev_name} 连接成功: local={self.local_port} remote={self.remote_port}")
|
|||
|
|
|
|||
|
|
#telnet
|
|||
|
|
#self.tn = telnetlib.Telnet("127.0.0.1",{self.remote_port},timeout=5)
|
|||
|
|
|
|||
|
|
|
|||
|
|
return True
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"[TCP-UART] {self.dev_name} 连接失败: {e}")
|
|||
|
|
return False
|
|||
|
|
'''
|
|||
|
|
# 去除转义FF的函数 2026/6/2,可能有安全问题
|
|||
|
|
def unescape_ff(raw:bytes)->bytes:
|
|||
|
|
buf = bytearray()
|
|||
|
|
i = 0
|
|||
|
|
n = len(raw)
|
|||
|
|
while i<n:
|
|||
|
|
buf.append(raw[i])
|
|||
|
|
|
|||
|
|
#当前字节FF,下一个字节FF:跳过下一个字节,只保留一个
|
|||
|
|
if raw[i] == 0xFF and i+1<n and raw[i+1]==0xFF:
|
|||
|
|
i +=1
|
|||
|
|
i +=1
|
|||
|
|
return bytes(buf)
|
|||
|
|
'''
|
|||
|
|
# 去除转义FF的函数 2026/6/2
|
|||
|
|
def unescape_ff(self, raw:bytes)->bytes:
|
|||
|
|
out = bytearray()
|
|||
|
|
idx=0
|
|||
|
|
length = len(raw)
|
|||
|
|
while idx<length:
|
|||
|
|
cur = raw[idx]
|
|||
|
|
out.append(cur)
|
|||
|
|
if cur == 0xff and (idx + 1 < length) and raw[idx+1]==0xff:
|
|||
|
|
idx+=1
|
|||
|
|
idx+=1
|
|||
|
|
return bytes(out)
|
|||
|
|
|
|||
|
|
def receive_loop(self):
|
|||
|
|
from midware.core.bus_udp_decoupler import bus_recv_queues
|
|||
|
|
from midware.config.base_config import DEVICE_CONFIG_DICT
|
|||
|
|
|
|||
|
|
while self.running:
|
|||
|
|
try:
|
|||
|
|
|
|||
|
|
#data = self.tn.read_some()
|
|||
|
|
|
|||
|
|
data = self.socket.recv(8192)#4096修改为16384 2026/5/12 tmy 65536->8192 2026/5/15
|
|||
|
|
if not data:
|
|||
|
|
time.sleep(0.001)
|
|||
|
|
continue
|
|||
|
|
self.tcp_buf += data #新数据追加到缓存尾部2026/6/2
|
|||
|
|
|
|||
|
|
dev_name = None
|
|||
|
|
protocol = None
|
|||
|
|
for name, cfg in DEVICE_CONFIG_DICT.items():
|
|||
|
|
if cfg.get("tcp_bus_port") == self.remote_port:
|
|||
|
|
dev_name = name
|
|||
|
|
protocol = cfg.get("protocol")
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
if not dev_name or not protocol:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
#循环拆包,大多数情况是只跑0~1次循环 2026/6/2
|
|||
|
|
while True:
|
|||
|
|
if len(self.tcp_buf)>self.MAX_LEN * 2:
|
|||
|
|
self.tcp_buf = self.tcp_buf[-1000:]
|
|||
|
|
h_pos = self.tcp_buf.find(self.HEAD)
|
|||
|
|
if h_pos ==-1:
|
|||
|
|
break
|
|||
|
|
#截断帧头前面垃圾
|
|||
|
|
if h_pos>0:
|
|||
|
|
self.tcp_buf = self.tcp_buf[h_pos:]
|
|||
|
|
#缓存不足最小帧,直接退出
|
|||
|
|
if(len(self.tcp_buf)<self.MIN_LEN):
|
|||
|
|
break
|
|||
|
|
#从帧头向后查找结束符号
|
|||
|
|
t_pos = self.tcp_buf.find(self.TAIL,2)
|
|||
|
|
if t_pos == -1:
|
|||
|
|
break
|
|||
|
|
frame = self.tcp_buf[:t_pos+2]
|
|||
|
|
#logger.info(f'去除转义FF帧前的有问题帧内容:{frame.hex()}')
|
|||
|
|
|
|||
|
|
if(self.MIN_LEN<= len(frame) <= self.MAX_LEN):
|
|||
|
|
#去除转义FF
|
|||
|
|
#logger.info(f'去除转义FF帧内容:')
|
|||
|
|
real_data = self.unescape_ff(frame)
|
|||
|
|
|
|||
|
|
#logger.info(f'去除转义FF帧内容:{real_data.hex()}')
|
|||
|
|
#入队
|
|||
|
|
try:
|
|||
|
|
q = bus_recv_queues.get(protocol)
|
|||
|
|
if q:
|
|||
|
|
try:
|
|||
|
|
q.put_nowait({
|
|||
|
|
"dev_name": dev_name,
|
|||
|
|
"raw_data": real_data,
|
|||
|
|
"protocol": protocol,
|
|||
|
|
})
|
|||
|
|
logger.debug(f'接受TCP重定向数据,存入bus_recv_queues,内容:{real_data.hex()}')
|
|||
|
|
except Full as e:
|
|||
|
|
print("队列已满",e)
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print("其他异常",repr(e))
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
#切掉已经解析的帧
|
|||
|
|
self.tcp_buf = self.tcp_buf[(t_pos+2) :]
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
'''
|
|||
|
|
# 匹配设备名
|
|||
|
|
dev_name = None
|
|||
|
|
protocol = None
|
|||
|
|
for name, cfg in DEVICE_CONFIG_DICT.items():
|
|||
|
|
if cfg.get("tcp_bus_port") == self.remote_port:
|
|||
|
|
dev_name = name
|
|||
|
|
protocol = cfg.get("protocol")
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
if not dev_name or not protocol:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
logger.info(f'接受TCP重定向数据,存入bus_recv_queues,内容:{data.hex()}')
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 推入现有接收队列(完全兼容你原有架构)
|
|||
|
|
q = bus_recv_queues.get(protocol)
|
|||
|
|
if q:
|
|||
|
|
try:
|
|||
|
|
q.put_nowait({
|
|||
|
|
"dev_name": dev_name,
|
|||
|
|
"raw_data": data,
|
|||
|
|
"protocol": protocol,
|
|||
|
|
})
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
'''
|
|||
|
|
except BlockingIOError:
|
|||
|
|
time.sleep(0.001)
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"[TCP-UART] {self.dev_name} 接收异常: {e}")
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
self.running = False
|
|||
|
|
|
|||
|
|
def start(self):
|
|||
|
|
if self.connect():
|
|||
|
|
self.thread = threading.Thread(target=self.receive_loop, daemon=True)
|
|||
|
|
self.thread.start()
|
|||
|
|
tcp_clients[self.dev_name] = self
|
|||
|
|
|
|||
|
|
def stop(self):
|
|||
|
|
self.running = False
|
|||
|
|
if self.socket:
|
|||
|
|
self.socket.close()
|
|||
|
|
|
|||
|
|
# ======================
|
|||
|
|
# 批量启动所有UART TCP客户端
|
|||
|
|
# ======================
|
|||
|
|
def start_all_tcp_uart_clients():
|
|||
|
|
from midware.config.base_config import DEVICE_CONFIG_DICT
|
|||
|
|
|
|||
|
|
for dev_name, cfg in DEVICE_CONFIG_DICT.items():
|
|||
|
|
tcp_local = cfg.get("tcp_local_port", 1)
|
|||
|
|
tcp_bus = cfg.get("tcp_bus_port", 1)
|
|||
|
|
|
|||
|
|
# 只启动端口 !=1 的UART设备
|
|||
|
|
if tcp_local != 1 and tcp_bus != 1:
|
|||
|
|
client = TCPUARTClient(
|
|||
|
|
dev_name=dev_name,
|
|||
|
|
local_port=tcp_local,
|
|||
|
|
remote_port=tcp_bus
|
|||
|
|
)
|
|||
|
|
client.start()
|
|||
|
|
time.sleep(0.1)
|