feat:初始化工程
This commit is contained in:
136
endpoint/mqtt_client.py
Normal file
136
endpoint/mqtt_client.py
Normal file
@@ -0,0 +1,136 @@
|
||||
import paho.mqtt.client as mqtt
|
||||
import uuid
|
||||
from config.logger_config import logger
|
||||
from config.setting import settings
|
||||
|
||||
|
||||
class MQTTClient:
|
||||
def __init__(self):
|
||||
self.broker_host = settings.mqtt_host
|
||||
self.broker_port = settings.mqtt_port
|
||||
self.client_id = self.generate_client_id()
|
||||
|
||||
self.client = mqtt.Client(client_id=self.client_id)
|
||||
|
||||
# 注册回调函数
|
||||
self.client.on_connect = self._on_connect
|
||||
self.client.on_disconnect = self._on_disconnect
|
||||
self.client.on_message = self._on_message
|
||||
|
||||
# 存储消息处理器的字典,键为主题,值为处理函数
|
||||
self.message_handlers = {}
|
||||
|
||||
self.connected = False
|
||||
|
||||
def _on_connect(self, client, userdata, flags, rc):
|
||||
"""连接回调函数"""
|
||||
self.connected = rc == 0
|
||||
if self.connected:
|
||||
logger.info(f"成功连接到MQTT broker {self.broker_host}:{self.broker_port}")
|
||||
else:
|
||||
logger.error(f"连接MQTT broker失败,错误代码: {rc}")
|
||||
|
||||
def _on_disconnect(self, client, userdata, rc):
|
||||
"""断开连接回调函数"""
|
||||
self.connected = False
|
||||
if rc != 0:
|
||||
logger.warning(f"意外断开与MQTT broker的连接,错误代码: {rc}")
|
||||
else:
|
||||
logger.info("已与MQTT broker断开连接")
|
||||
|
||||
def _on_message(self, client, userdata, msg):
|
||||
"""消息接收回调函数"""
|
||||
logger.info(f"收到消息: {msg.topic}")
|
||||
try:
|
||||
if msg.topic in self.message_handlers:
|
||||
self.message_handlers[msg.topic](client, msg)
|
||||
else:
|
||||
logger.warning(f"未找到 {msg.topic} 的消息处理器")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"处理消息时出错: {str(e)}", exc_info=True)
|
||||
|
||||
@staticmethod
|
||||
def generate_client_id(prefix: str = "client") -> str:
|
||||
"""生成唯一客户端ID"""
|
||||
uuid_str = str(uuid.uuid4()).split('-')[0]
|
||||
return f"{prefix}-{uuid_str}"
|
||||
|
||||
def add_message_handler(self, topic, handler):
|
||||
"""添加消息处理器"""
|
||||
if topic in self.message_handlers:
|
||||
logger.warning(f"主题 {topic} 已存在处理器,将被覆盖")
|
||||
self.message_handlers[topic] = handler
|
||||
logger.info(f"为主题 {topic} 注册了消息处理器")
|
||||
logger.debug(f"当前消息处理器: {self.message_handlers.keys()}")
|
||||
|
||||
def connect(self):
|
||||
"""连接到MQTT服务器"""
|
||||
try:
|
||||
self.client.connect(self.broker_host, self.broker_port)
|
||||
self.start_loop()
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"连接MQTT broker {self.broker_host}:{self.broker_port}时发生错误: {str(e)}", exc_info=True)
|
||||
return False
|
||||
|
||||
def disconnect(self):
|
||||
"""断开与MQTT服务器的连接"""
|
||||
try:
|
||||
self.stop_loop()
|
||||
self.client.disconnect()
|
||||
logger.info("正在断开与MQTT broker的连接")
|
||||
except Exception as e:
|
||||
logger.error(f"断开连接时发生错误: {str(e)}", exc_info=True)
|
||||
|
||||
def subscribe(self, topic, qos=0):
|
||||
"""订阅主题"""
|
||||
try:
|
||||
result, mid = self.client.subscribe(topic, qos)
|
||||
if result == mqtt.MQTT_ERR_SUCCESS:
|
||||
logger.info(f"已订阅主题: {topic} (QoS: {qos})")
|
||||
return True
|
||||
else:
|
||||
logger.error(f"订阅主题 {topic} 失败,错误代码: {result}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"订阅主题时发生错误: {str(e)}", exc_info=True)
|
||||
return False
|
||||
|
||||
def publish(self, topic, payload, qos=0, retain=False):
|
||||
"""发布消息到指定主题"""
|
||||
if not self.connected:
|
||||
logger.warning("未连接到MQTT broker,无法发布消息")
|
||||
return False
|
||||
|
||||
try:
|
||||
result = self.client.publish(topic, payload, qos, retain)
|
||||
result.wait_for_publish()
|
||||
if result.rc == mqtt.MQTT_ERR_SUCCESS:
|
||||
logger.debug(f"已发布消息到主题 {topic}: {payload}")
|
||||
return True
|
||||
else:
|
||||
logger.error(f"发布消息到主题 {topic} 失败,错误代码: {result.rc}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"发布消息时发生错误: {str(e)}", exc_info=True)
|
||||
return False
|
||||
|
||||
def start_loop(self):
|
||||
"""启动MQTT网络循环"""
|
||||
try:
|
||||
self.client.loop_start()
|
||||
logger.info("已启动MQTT网络循环")
|
||||
except Exception as e:
|
||||
logger.error(f"启动网络循环时发生错误: {str(e)}", exc_info=True)
|
||||
|
||||
def stop_loop(self):
|
||||
"""停止MQTT网络循环"""
|
||||
try:
|
||||
self.client.loop_stop()
|
||||
logger.info("已停止MQTT网络循环")
|
||||
except Exception as e:
|
||||
logger.error(f"停止网络循环时发生错误: {str(e)}", exc_info=True)
|
||||
|
||||
|
||||
mqtt_client = MQTTClient()
|
||||
84
endpoint/tcp_server.py
Normal file
84
endpoint/tcp_server.py
Normal file
@@ -0,0 +1,84 @@
|
||||
import asyncio
|
||||
import signal
|
||||
import platform
|
||||
from config.logger_config import logger
|
||||
from config.setting import settings
|
||||
from model.index import UNKNOWN_MESSAGE
|
||||
from processor.tcp_processor import TcpMessageProcessor
|
||||
|
||||
|
||||
class TCPServer:
|
||||
def __init__(self):
|
||||
self.host = settings.tcp_host
|
||||
self.port = settings.tcp_port
|
||||
self.server = None
|
||||
self.clients = set()
|
||||
self.running = False
|
||||
self.message_processor = TcpMessageProcessor()
|
||||
|
||||
async def handle_client(self, reader, writer):
|
||||
"""处理客户端连接"""
|
||||
addr = writer.get_extra_info('peername')
|
||||
logger.info(f"新客户端连接: {addr}")
|
||||
self.clients.add(writer)
|
||||
|
||||
try:
|
||||
while self.running:
|
||||
data = await reader.read(1024)
|
||||
if not data:
|
||||
break # 连接断开
|
||||
|
||||
message = data.decode('utf-8').strip()
|
||||
logger.info(f"收到 {addr} 的消息: {message}")
|
||||
|
||||
# 放到消息处理器里面处理
|
||||
response = self.message_processor.process(message)
|
||||
|
||||
# 回复消息
|
||||
if response != UNKNOWN_MESSAGE:
|
||||
writer.write(response.encode())
|
||||
await writer.drain()
|
||||
logger.info(f"回复 {addr}: {response}")
|
||||
except Exception as e:
|
||||
logger.error(f"客户端 {addr} 处理错误: {e}")
|
||||
finally:
|
||||
if writer in self.clients:
|
||||
self.clients.remove(writer)
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
logger.warning(f"客户端 {addr} 断开")
|
||||
|
||||
async def start(self):
|
||||
"""启动服务器"""
|
||||
self.running = True
|
||||
self.server = await asyncio.start_server(self.handle_client, self.host, self.port)
|
||||
|
||||
# 仅在非Windows平台设置信号处理
|
||||
if platform.system() != 'Windows':
|
||||
loop = asyncio.get_running_loop()
|
||||
for sig in (signal.SIGINT, signal.SIGTERM):
|
||||
loop.add_signal_handler(sig, self.stop)
|
||||
|
||||
logger.info(f"TCP服务器已启动 {self.host}:{self.port}")
|
||||
async with self.server:
|
||||
await self.server.serve_forever()
|
||||
|
||||
async def _safe_stop(self):
|
||||
"""安全的停止服务器"""
|
||||
self.running = False
|
||||
if self.server:
|
||||
self.server.close()
|
||||
await self.server.wait_closed()
|
||||
|
||||
# 关闭所有客户端连接
|
||||
for writer in list(self.clients):
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
|
||||
def stop(self):
|
||||
"""停止服务器"""
|
||||
logger.info("正在关闭TCP服务器...")
|
||||
asyncio.create_task(self._safe_stop())
|
||||
|
||||
|
||||
tcp_server = TCPServer()
|
||||
Reference in New Issue
Block a user