socket_client.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. '''
  2. Author: zhaoyong 77912776@qq.com
  3. Date: 2025-08-14 22:19:23
  4. LastEditTime: 2025-08-24 14:21:05
  5. LastEditors: zhaoyong 77912776@qq.com
  6. FilePath: \robot_ai\core\socket_client.py
  7. Description: 头部注释配置模板
  8. '''
  9. """
  10. Socket客户端连接管理模块
  11. """
  12. import time
  13. from utils.logger import logger
  14. import struct
  15. from socket import socket, AF_INET, SOCK_STREAM, timeout
  16. from threading import Thread, Event
  17. from typing import Optional, Tuple
  18. from utils.network import ping_host
  19. from config.config.settings import config
  20. class SocketClient:
  21. """Socket客户端连接管理类"""
  22. def __init__(self):
  23. self.client_socket: Optional[socket] = None
  24. self.server_address = config.SERVER_ADDRESS
  25. self.connected_event = Event()
  26. self.stop_event = Event()
  27. self.connect()
  28. self.start_ping_check()
  29. def connect(self) -> None:
  30. """建立连接"""
  31. while not self.stop_event.is_set():
  32. try:
  33. if self.client_socket:
  34. self.client_socket.close()
  35. self.client_socket = socket(AF_INET, SOCK_STREAM)
  36. self.client_socket.settimeout(config.CONNECTION_TIMEOUT)
  37. self.client_socket.connect(self.server_address)
  38. logger.info(f"已连接到讯飞套件: {self.server_address}")
  39. self.client_socket.settimeout(None) # 连接成功后取消超时
  40. self.connected_event.set()
  41. break
  42. except (ConnectionError, OSError, timeout) as e:
  43. logger.error(
  44. f"讯飞套件 {self.server_address} 连接失败: {e}. {config.RECONNECT_DELAY}秒后重试...")
  45. # 摄像头连接失败播放提示音
  46. from utils.tts_client import play_text_async
  47. play_text_async('讯飞套件连接失败,请检查讯飞套件是否正常', use_cache=True)
  48. self.connected_event.clear()
  49. time.sleep(config.RECONNECT_DELAY)
  50. def receive_full_data(self, expected_length: int) -> Optional[bytes]:
  51. """
  52. 接收完整数据
  53. Args:
  54. expected_length: 期望接收的数据长度
  55. Returns:
  56. Optional[bytes]: 接收到的数据,失败时返回None
  57. """
  58. received_data = bytearray()
  59. while len(received_data) < expected_length:
  60. try:
  61. chunk = self.client_socket.recv(
  62. expected_length - len(received_data))
  63. if not chunk:
  64. return None
  65. received_data.extend(chunk)
  66. except timeout:
  67. return None
  68. return bytes(received_data)
  69. def start_ping_check(self) -> None:
  70. """启动心跳检测"""
  71. Thread(target=self.ping_check, daemon=True).start()
  72. def ping_check(self) -> None:
  73. """心跳检测循环"""
  74. while not self.stop_event.is_set():
  75. try:
  76. if not ping_host(self.server_address[0]):
  77. logger.error(
  78. f"Ping检测失败: {self.server_address[0]}. 重新连接...")
  79. self.connected_event.clear()
  80. self.connect()
  81. except Exception as e:
  82. logger.error(f"心跳检测异常: {e}")
  83. time.sleep(config.PING_INTERVAL)
  84. def close(self) -> None:
  85. """关闭连接"""
  86. self.stop_event.set()
  87. if self.client_socket:
  88. self.client_socket.close()
  89. logger.info("Socket连接已关闭")
  90. def is_connected(self) -> bool:
  91. """检查是否已连接"""
  92. return self.connected_event.is_set()
  93. def get_socket(self) -> Optional[socket]:
  94. """获取socket对象"""
  95. return self.client_socket if self.is_connected() else None