6.4.1 监听连接

监听连接是 MySQL 服务的入口,其核心是 Connection_acceptor 模板类与 Mysqld_socket_listener 类协同工作的 connection_event_loop 事件循环。整个过程可分为初始化、循环监听与接受、分发处理三个阶段。

🚀 阶段一:网络初始化 (Network Initialization)

mysqld_main 函数完成一系列初始化后,会调用 network_init 来建立服务端的监听套接字(Socket)。

  1. 创建套接字
    • 根据配置,为 TCP/IP 协议(默认3306端口)创建套接字,会优先尝试 IPv4,若失败则尝试 IPv6。
    • 同时,也会为本地连接的 Unix Socket(类Unix系统)或 Windows Named Pipe 创建监听套接字。
  2. 绑定与监听
    • 将套接字绑定(bind)到指定的 IP 地址和端口。
    • 调用 listen 使套接字进入监听状态,等待客户端的连接请求。

如果 MySQL 异常退出后快速重启,可能出现端口被旧进程占用导致绑定失败的情况。此时 MySQL 会进入循环等待,直到端口被释放或超过 --port-open-timeout 设定的超时时间。

🔁 阶段二:事件循环与连接接受

完成初始化后,程序会进入由 Connection_acceptor 管理的核心事件循环 connection_event_loop,其核心任务是循环监听并接受新连接

  • 事件循环机制

    • 在循环中,会不断调用 Mysqld_socket_listener 对象的 listen_for_connection_event 方法。
    • 该方法底层使用 pollselect 系统调用来监听套接字上的 I/O 事件。MySQL 选择 poll/select 而非 epoll,主要是为了跨平台的可移植性。
  • 接受新连接

    • poll/select 检测到监听套接字上有新连接到达时,listen_for_connection_event 会调用 mysql_socket_accept 接受连接。
    • 成功接受后,会创建一个 Channel_info 对象,它像一个"数据包",封装了本次连接的所有信息,如客户端的 socket 文件描述符、IP 和端口等。

⚙️ 阶段三:连接处理与分发

获取到封装了连接信息的 Channel_info 对象后,核心处理流程转向 Connection_handler_manager 类。

  1. 连接数检查Connection_handler_manager 会调用 check_and_incr_conn_count 检查当前连接数。若已达到 max_connections 限制,新连接会被拒绝(但会为 root 用户预留一个额外的连接通道用于紧急管理)。

  2. 分发与创建线程 :连接数检查通过后,管理器会调用 add_connection 方法。这一步会分发到具体的 Connection_handler 实现。

    • 默认的 Per_thread_connection_handler 会为每个新连接创建一个线程。为了优化性能,会优先尝试从 thread_cache 中复用空闲线程。
    • 新线程(无论是新建还是复用)的入口函数是 handle_one_connection(或 handle_connection)。这个线程随后会负责该连接整个生命周期的所有操作。

    值得一提的是,MySQL 5.7 对此流程进行了优化,将 THD(线程描述符)、NETVIO 等会话对象的初始化工作交给了新创建的用户线程自身去完成,使得主线程能更专注于高效接受新连接。

🤝 连接线程的后续任务

新线程启动后,会执行一系列初始化,并与客户端完成握手认证:

  • 初始化会话与网络对象 :线程入口函数会初始化 THD(线程描述符)、VIO(虚拟I/O)和 NET 等关键对象。其中 VIO 是对底层 Socket 的抽象,提供了 vio_readvio_write 等回调函数。同时,连接 socket 会被设置为非阻塞模式O_NONBLOCK)。
  • 握手与认证
    1. 发送握手包 :服务端向客户端发送一个包含挑战码(scramble) 的握手初始化包。
    2. 客户端响应:客户端使用挑战码加密密码,将加密后的密码连同用户名等信息打包发回服务端。
    3. 服务端验证:服务端解密并验证密码,检查用户账户和权限。
    4. 返回结果 :验证通过则返回 OK 包,连接成功建立;否则返回 ERROR 包。
  • 进入命令循环 :认证通过后,线程便进入 do_command 循环,持续读取、解析并执行客户端发来的 SQL 命令。

💎 总结

MySQL 的监听连接机制,是一套经过精心设计的、清晰优雅的事件驱动模型。其核心流程可以概括为:

  1. 准备mysqld_main 启动后,通过 network_init 创建并配置好监听套接字。
  2. 循环 :进入 connection_event_loop,主线程通过 poll/select 高效地等待新连接。
  3. 接受 :当新连接到达,主线程将其接受,并封装为 Channel_info 对象。
  4. 分发Connection_handler_manager 检查连接数限制后,将连接分发出去。
  5. 处理:通常由独立的线程接管连接,完成握手认证,最后进入 SQL 命令的处理循环。

这一系列流程,共同构成了 MySQL 能够处理成千上万并发连接的基础。

java 复制代码
/**
 连接接受器循环以接受来⾃客户端的连接
    Connection acceptor loop to accept connections from clients.
  */
  void connection_event_loop() {
    Connection_handler_manager *mgr =
        Connection_handler_manager::get_instance();
    while (!connection_events_loop_aborted()) {
      // 监听连接事件
      Channel_info *channel_info = m_listener-
>listen_for_connection_event();
      // 处理⼀个新的连接
      if (channel_info != nullptr) mgr-
>process_new_connection(channel_info);
   }
相关推荐
mldong1 小时前
会签三兄弟:并行/串行/按比例的实现与取舍
java·架构
桐桐桐1 小时前
Python 实战:批量生成带来源参数的 WhatsApp 短链 + 二维码
服务器·数据库·python·前端框架·ip·跨境电商·独立站
stereohomology1 小时前
AI解读:某IM软件本地数据库密钥提取与解密
数据库·攻防·加密解密·数字平权
Java后端的Ai之路1 小时前
01、Python - 设计模式介绍
java·人工智能·python·设计模式·通用
zzzll11111 小时前
大模型技术原理与应用实践
java·数据库·人工智能
倔强的石头_1 小时前
数据库迁移工具从单机作业走向云端协同
数据库
yours_Gabriel1 小时前
【一】数据库基础:SQL语句、函数、约束、多表查询、事务
数据库·sql·oracle
asdfg12589631 小时前
java.util包中的ArrayList&&Collections的目的和用途
java·arraylist·collections
余额瞒着我当琳1 小时前
C++STL--list底层实现,迭代器分类,模拟list的迭代器封装、实现
java·开发语言·c++