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);
   }
相关推荐
卓怡学长4 小时前
w233基于vue和springboot的宠物管理系统的设计与实现
java·vue.js·spring boot·spring·intellij-idea
我命由我123455 小时前
人脸识别 - 去重时间窗口
java·开发语言·python·学习·java-ee·学习方法·python3.11
逆境不可逃5 小时前
Pi Agent 学习笔记:一次提问背后的工具调用循环
java·笔记·学习
落魄大学生之流水线上谋生计5 小时前
Java并发核心机制详解:线程池、CAS、AQS、锁升级
java·开发语言·数据库
aosky5 小时前
Linux 写内容到文件的几种方式
java·linux·服务器
Wang's Blog6 小时前
Java框架快速入门: Spring Security+OAuth2之邮件验证码发送(SMTP与API方式)
java·数据库·spring
砚底藏山河7 小时前
容错重试与指数退避:网络抖动手抖不再丢数据(魔码量化实战 #04)
java·数据库·python·金融
2501_930472447 小时前
云安全自查清单:用腾讯云助手 30 分钟完成一次权限与密钥体检
java·腾讯云
蓝速科技7 小时前
会议室门牌触控预约选型与落地实战指南丨蓝速科技
大数据·运维·数据库·人工智能·科技
YIAN7 小时前
手撸社区后端:一套可落地的用户 - 文章 - 互动体系 MySQL 表设计与优化思路
后端·mysql