handle_connections_socket函数

本文介绍MySQL如何通过创建或分配线程来处理客户端连接请求。详细解释了MySQL利用select和accept函数监听并接收请求的过程,以及根据配置文件选择使用缓存线程或创建新线程的方式。

函数所在文件:mysqld.cc

该函数用于处理客户端的请求,当一个请求到达时,需要为该请求分配或新建一个线程

运行一个while循环来接受请求:

 while (!abort_loop) //当需要退出时置1
在循环体内使用select函数来对请求进行监听:
select((int) max_used_connection,&readFDs,0,0,0)
设置服务器socket为非阻塞模式:
  fcntl(sock, F_SETFL, flags | O_NONBLOCK);

再使用标准库函数accept接受请求:

  new_sock = accept(sock, my_reinterpret_cast(struct sockaddr *) (&cAddr),&length);

当完成select()/accecpt()等操作后,分配一个THD实例:

    if (!(thd= new THD))
    {
      (void) shutdown(new_sock, SHUT_RDWR);
      VOID(closesocket(new_sock));
      continue;
    }

打开连接,读取fcntl状态,并初始化任务线程描述符的网络操作:

    if (!(vio_tmp=vio_new(new_sock,
			  sock == unix_sock ? VIO_TYPE_SOCKET :
			  VIO_TYPE_TCPIP,
			  sock == unix_sock ? VIO_LOCALHOST: 0)) ||
	my_net_init(&thd->net,vio_tmp))

最后,调用函数创建一个新的线程:

create_new_thread(thd);

在上述函数中,有两种可能分配线程:

1.使用缓存中的线程来分配

2.创建一个新的线程

具体实现取决于配置文件,无论何种情况,都会为这个新的请求赋予一个线程id

  thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;

  thread_count++;

  thread_scheduler.add_connection(thd);
全局变量thread_scheduler用于管理线程的建立,在一个连接一个线程的情况下,将调用函数:
void create_thread_to_handle_connection(THD *thd)

当一个停用线程缓存或线程缓存中暂无可用线程时,将要创建一个新的线程,相关代码如下:
  if (cached_thread_count > wake_thread)
  {
    /* Get thread from cache */
    thread_cache.append(thd);
    wake_thread++;
    pthread_cond_signal(&COND_thread_cache);
  }
  else
  {
    char error_message_buff[MYSQL_ERRMSG_SIZE];
    /* Create new thread to handle connection */
    int error;
    thread_created++;
    threads.append(thd);
    DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id));
    thd->connect_utime= thd->start_utime= my_micro_time();
    if ((error=pthread_create(&thd->real_id,&connection_attrib,
                              handle_one_connection,
                              (void*) thd)))

    ……

新分配的线程从文件handle_one_connection()开始执行后续的一系列操作.

class SocketStatus(Enum): """连接状态枚举,提高代码可读性""" OFFLINE = "Offline" CONNECTING = "Connecting" RECONNECT = "ReConnect" RECONNECT_ERROR = "ReConnect_error" CONNECT_WAIT_FOR_FLAG = "CONNECT_WAIT_FOR_FLAG" CONNECT_WAIT_FOR_0X05 = "Connect_wait_for_0x05" CONNECT_WAIT_FOR_0X06 = "Connect_wait_for_0x06" CONNECT_WAIT_FOR_0X09 = "Connect_wait_for_0x09" CONNECT_WAIT_FOR_0X0A = "Connect_wait_for_0x0A" CONNECT_WAIT_FOR_0X13 = "Connect_wait_for_0x13" CONNECT_WAIT_FOR_0X55 = "Connect_wait_for_0x55" CONNECT_WAIT_FOR_0X56 = "Connect_wait_for_0x56" ONLINE = "Online" class AsyncSocketWriter: """异步Socket发送器 - 专门负责数据发送""" def __init__(self, writer, pileCode, message_id, total, connections, logger): self.writer = writer self.pileCode = pileCode self.message_id = message_id self.start = " " self.dataLen = " " self.serialNum = "" self.encryption = " " self.Type = " " self.pileType = " " self.chargingGunNum = " " self.protocolVersion = " " self.programVersion = "" self.netType = " " self.SIMCard = " " self.carrier = " " self.modelCode = " " self.charging = False self.running = True self.total = total self.time_count = 0 self.logger = logger self.connections = connections[pileCode] self._write_lock = asyncio.Lock() self._status_handlers = { SocketStatus.OFFLINE: self._handle_offline_status, SocketStatus.CONNECTING: self._handle_connecting_status, SocketStatus.RECONNECT: self._handle_reconnect_status, SocketStatus.RECONNECT_ERROR: self._handle_reconnect_error_status, SocketStatus.CONNECT_WAIT_FOR_FLAG: self._handle_wait_for_flag, SocketStatus.CONNECT_WAIT_FOR_0X05: self._handle_wait_for_0x05, SocketStatus.CONNECT_WAIT_FOR_0X06: self._handle_wait_for_0x06, SocketStatus.CONNECT_WAIT_FOR_0X09: self._handle_wait_for_0x09, SocketStatus.CONNECT_WAIT_FOR_0X0A: self._handle_wait_for_0x0A, SocketStatus.CONNECT_WAIT_FOR_0X13: self._handle_wait_for_0x13, SocketStatus.CONNECT_WAIT_FOR_0X55: self._handle_wait_for_0x55, SocketStatus.CONNECT_WAIT_FOR_0X56: self._handle_wait_for_0x56, SocketStatus.ONLINE: self._handle_online_status } self.send_0x13_flag = False async def start_write(self): self.logger.info(f'✅Socket {self.message_id} 桩号: {self.pileCode} 正在等待发送报文序列') while self.running: try: await self._process_status() await asyncio.sleep(0.5) except asyncio.CancelledError: break except Exception as e: raise e class AsyncSocketReader: """异步Socket读取器 - 专门负责数据接收""" def __init__(self, reader, pileCode, message_id, connections, logger): self.reader = reader self.pileCode = pileCode self.message_id = message_id self.running = True self.connections = connections[pileCode] self._reader_lock = asyncio.Lock() self.logger = logger # 报文处理器映射 self._message_handlers = { 0x02: self._handle_login_message, 0x04: self._handle_status_message, 0x06: self._handle_billing_model_message, 0x56: self._handle_unknown_message_56, 0x0A: self._handle_price_model_message, 0x9C: self._handle_unknown_message_9C } self.flag_0x0A = False self.flag_0x56 = False self.flag_0x13 = False async def start_reading(self): global logger while self.running: try: await self._read_and_process() await asyncio.sleep(0.5) except Exception as e: raise e class AsyncSocketManager: """异步Socket管理器 - 协调Reader和Writer线程""" def __init__(self): self.running = True self._shutdown_event = asyncio.Event() self._cleanup_lock = asyncio.Lock() self.shutdown_requested = asyncio.Event() self.original_sigint_handler = None self.shutdown_requested = asyncio.Event() self.server_config = {'ip': 'xxx.com', 'port': 5455} self.total = 0 self.writer = None self.reader = None self._active_tasks = set() self.connections: Dict[str, Dict] = {} self.tasks: List[asyncio.Task] = [] self._read_lock = asyncio.Lock() # 读取操作专用锁 self._write_lock = asyncio.Lock() # 写入操作专用锁 self._state_lock = asyncio.Lock() # 状态变更锁 self.logger = logging.getLogger(__name__) self.setup_logging() self.connections_count = 0 async def socket_worker(self, message_id: str, pileCode: str, total: int): global logger """异步Socket工作协程""" current_times = 0 while self.running and not self._shutdown_event.is_set(): try: writer, reader = await self.create_socket_connection(self.server_config, message_id, pileCode) if writer is not None and reader is not None: self.writer, self.reader = AsyncSocketWriter(writer, pileCode, message_id, self.total, self.connections, self.logger), AsyncSocketReader( reader, pileCode, message_id, self.connections, self.logger) if current_times == 0: activeNum = len(list(filter(lambda conn: conn.get('isLogin', False), self.connections.values()))) self.logger.info(f'🌍 现有连接 {activeNum} / {self.total}') current_times = time.time() elif time.time() - current_times > 6: activeNum = len(list(filter(lambda conn: conn.get('isLogin', False), self.connections.values()))) self.logger.info(f'🌍 现有连接 {activeNum} / {self.total}') current_times = time.time() if self.writer is not None and self.reader is not None: # 并发启动读写任务 read_task = asyncio.create_task( self.reader.start_reading(), name=f"reader_{pileCode}_{message_id}" ) write_task = asyncio.create_task( self.writer.start_write(), name=f"writer_{pileCode}_{message_id}" ) # 添加到实例级别的活跃任务集合 self._active_tasks.add(read_task) self._active_tasks.add(write_task) await asyncio.gather( read_task, write_task, return_exceptions=True ) except asyncio.CancelledError: self.logger.info("Socket工作协程被取消") except Exception as e: self.logger.error(f"❌Socket {message_id} 桩号: {pileCode} 工作线程异常: {e}") if pileCode in self.connections: if self.connections[pileCode]['writer'] is not None: try: self.connections[pileCode]['writer'].close() await self.connections[pileCode]['writer'].wait_closed() except Exception as close_error: self.logger.error( f"❌ 发生错误 {e} 而关闭Socket {message_id} 桩号: {pileCode} 失败: {close_error}") del self.connections[pileCode] self.logger.info(f"✅发生错误 {e} 原因Socket {message_id} 桩号: {pileCode} 连接已关闭") await asyncio.sleep(20) # 异常后等待20秒重试 except KeyboardInterrupt: self.logger.error("接收到中断信号...") break async def start_multiple_connections(self, piles_list_config): """异步启动多个Socket连接""" for i, pileCode in enumerate(piles_list_config): task = asyncio.create_task( self.socket_worker( f"conn_{i + 1}", pileCode, len(piles_list_config)) ) self.total = len(piles_list_config) self.tasks.append(task) self.logger.info( f"启动异步Socket连接 {i + 1} 到 {self.server_config['ip']}:{self.server_config['port']} 桩号: {pileCode}") async def create_socket_connection(self, server_config: Dict, message_id: str, pileCode: str): global logger """创建单个socket连接并处理通信""" try: """创建异步Socket连接""" reader, writer = await asyncio.wait_for( asyncio.open_connection(server_config['ip'], server_config['port']), timeout=60.0 ) self.logger.info( f"异步Socket {message_id} 桩号: {pileCode} " f"成功连接到 {server_config['ip']}:{server_config['port']}" ) # 存储连接信息 self.connections[pileCode] = { 'reader': reader, 'writer': writer, 'pileCode': pileCode, 'message_id': message_id, 'config': server_config, 'last_heartbeat1': 0, 'last_heartbeat2': 0, 'last_time_stamp': 0, 'isLogin': False, 'timeout_count_login': 0, 'timeout_count': 0, 'heart_serialNum': "00 00", 'status': 'Offline', 'charging': False, 'priceModelList': [] } return writer, reader except asyncio.TimeoutError: if pileCode in self.connections: if self.connections[pileCode]['writer'] is not None: try: self.connections[pileCode]['writer'].close() await self.connections[pileCode]['writer'].wait_closed() except Exception as close_error: self.logger.error(f"❌ 超时而关闭Socket {message_id} 桩号: {pileCode} 失败: {close_error}") if pileCode in self.connections: del self.connections[pileCode] self.logger.info(f"✅超时原因 Socket {message_id} 桩号: {pileCode} 连接已关闭") self.logger.error(f"⛔Socket {message_id} 桩号: {pileCode} 连接超时") except ConnectionRefusedError: if pileCode in self.connections: if self.connections[pileCode]['writer'] is not None: try: self.connections[pileCode]['writer'].close() await self.connections[pileCode]['writer'].wait_closed() except Exception as close_error: self.logger.error(f"❌ 连接拒绝而关闭Socket {message_id} 桩号: {pileCode} 失败: {close_error}") if pileCode in self.connections: del self.connections[pileCode] self.logger.info(f"✅连接拒绝原因 Socket {message_id} 桩号: {pileCode} 连接已关闭") self.logger.error(f"🚫Socket {message_id} 桩号: {pileCode} 连接被拒绝") except Exception as e: if pileCode in self.connections: if self.connections[pileCode]['writer'] is not None: try: self.connections[pileCode]['writer'].close() await self.connections[pileCode]['writer'].wait_closed() except Exception as close_error: self.logger.error( f"❌ 发生错误 {e} 而关闭Socket {message_id} 桩号: {pileCode} 失败: {close_error}") if pileCode in self.connections: del self.connections[pileCode] self.logger.info(f"❌发生错误 {e} 原因Socket {message_id} 桩号: {pileCode} 连接已关闭") self.logger.error(f"❌Socket {pileCode} 桩号: {pileCode} 发生错误: {e}") except KeyboardInterrupt: self.logger.info("接收到中断信号...") def read_to_array(file_path, remove_empty=True, encoding='utf-8'): """ 读取txt文件到数组 参数: file_path: 文件路径 remove_empty: 是否移除空行 encoding: 文件编码 """ try: with open(file_path, 'r', encoding=encoding) as file: if remove_empty: lines = [line.strip() for line in file if line.strip()] else: lines = [line.strip() for line in file] # 对每行数据进行处理 processed_lines = [] for line in lines: if len(line) == 14 and line.isdigit(): # 将14位数字分割为每2位一组 parts = [line[i:i + 2] for i in range(0, 14, 2)] processed_line = ' '.join(parts) processed_lines.append(processed_line) else: processed_lines.append(line) return processed_lines except FileNotFoundError: print(f"❌错误: 文件 '{file_path}' 不存在") return [] except UnicodeDecodeError: print(f"❌错误: 使用 {encoding} 编码读取文件失败") return [] except Exception as e: print(f"❌未知错误: {e}") return [] async def async_main(): # 定义多个桩号配置 piles_list_config = read_to_array('pileList.txt') if not piles_list_config: print("⚠️ 桩号配置文件为空或无有效数据") return # 创建多socket客户端实例 manager = AsyncSocketManager() # 创建优雅关闭管理器 manager.install_signal_handlers() try: # 启动多个连接 print("启动多个socket连接...") await manager.start_multiple_connections(piles_list_config) # 使用事件等待替代while循环 logger.info("✅ 所有连接已启动,等待工作完成或关闭信号...") await manager.shutdown_requested.wait() logger.info("🔄 接收到关闭信号,开始清理流程...") except asyncio.CancelledError: logger.info("异步任务被取消") # 重新抛出以便上层处理 raise "异步任务被取消" except KeyboardInterrupt: logger.info("接收到键盘中断信号") # 不直接处理,让信号处理器处理 except Exception as e: logger.error(f"❌ 异步Socket客户端异常: {e}") finally: # 确保资源清理 logger.info("开始最终资源清理...") await manager.close_all_connections() manager.restore_signal_handlers() logger.info("✅ 异步Socket客户端已完全关闭") def main(): """主入口函数""" try: asyncio.run(async_main()) except KeyboardInterrupt: logger.info("程序被用户中断") except Exception as e: logger.error(f"程序异常退出: {e}") return 1 return 0 if __name__ == "__main__": exit(main()) 优化以上代码,给出完整代码
最新发布
11-07
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值