memcached 的源码中,conn_state 枚举用于表示连接的状态机。这一状态机由 drive_machine() 函数驱动,控制了客户端请求从建立连接、读取命令、执行命令、写回响应、直到关闭连接的整个过程。以下为 memcached.hmemcached.c 中对该状态枚举的定义与使用说明:

// memcached.h
typedef enum conn_state {
    conn_listening,  // 正在监听连接(仅用于主线程)
    conn_new_cmd,    // 等待新的命令输入
    conn_waiting,    // 等待下一次可读事件
    conn_read,       // 正在读取数据
    conn_parse_cmd,  // 解析命令
    conn_write,      // 将响应写回客户端
    conn_nread,      // 读取命令数据(如 SET 的 value 部分)
    conn_swallow,    // 丢弃多余的数据
    conn_closing,    // 正在关闭连接
    conn_mwrite,     // 批量写响应(通过 iovec)
    conn_closed,     // 连接已关闭,等待释放
    conn_watch,      // 观察状态(例如触发事件后等待处理)
    conn_io_queue    // 加入 I/O 队列中等待处理
} conn_state;

这些状态与状态名数组 statenames[] 一一对应:

// memcached.c
const char *const statenames[] = {
    "conn_listening",
    "conn_new_cmd",
    "conn_waiting",
    "conn_read",
    "conn_parse_cmd",
    "conn_write",
    "conn_nread",
    "conn_swallow",
    "conn_closing",
    "conn_mwrite",
    "conn_closed",
    "conn_watch",
    "conn_io_queue"
};

这些状态主要用于 drive_machine() 中的状态切换处理。下面对各状态的含义和作用进行简要说明:

各连接状态说明

状态 含义
conn_listening 主线程使用,监听客户端连接(通过 listen()accept() 实现)
conn_new_cmd 客户端连接建立后进入此状态,准备接收新命令
conn_waiting 当前无数据可读时挂起,等待下一次可读事件
conn_read 从客户端读取请求数据,可能是命令头或正文
conn_parse_cmd 尝试从读取缓冲区中解析出一条完整的命令
conn_nread 读取命令体的数据,例如 SET 命令的 value 部分
conn_swallow 丢弃客户端多发的数据,通常用于异常恢复
conn_write 将处理结果写回客户端
conn_mwrite 使用 writev 将多个响应分片写回客户端,提高写入效率
conn_closing 连接准备关闭,清理连接资源
conn_closed 标志连接已完全关闭,内存即将被释放
conn_watch 异步状态,用于观察外部事件(如外部回调完成)
conn_io_queue 加入 I/O 队列,等待异步处理

状态转移流程(标准路径)

conn_listening
    ↓ accept()
conn_new_cmd
    ↓ 收到事件后读取数据
conn_read → conn_parse_cmd
    ↓             ↓
conn_nread   ←→   conn_swallow
    ↓
conn_write / conn_mwrite
    ↓
conn_closing → conn_closed

状态转换触发机制

状态切换主要在 drive_machine() 函数中执行。每个连接对象 conn 都绑定了一个状态字段 c->state

在主循环中会根据当前状态进入对应处理逻辑,例如:

switch (c->state) {
    case conn_read:
        if (IS_UDP(c)) {
            ...
        } else {
            res = try_read_network(c);
        }
        if (res == READ_DATA_RECEIVED) {
            c->state = conn_parse_cmd;
        }
        break;
    ...
}

设计特点

  • 状态机是非阻塞设计的核心,每次状态处理都是“走一步停一下”,不依赖系统阻塞调用。

  • 不同状态可由事件触发器(如 epoll)调度,保证高并发性能。

  • 每次状态切换尽可能做最小处理,保持响应快速。

  • 异步写、异步读、协议解析与命令处理分离,提高可维护性。

示例:读命令流程简析

以一个简单的 GET 命令为例,流程大致如下:

1. conn_listening(主线程监听)
2. accept() → conn_new_cmd(worker线程接管)
3. conn_read → 从 socket 读取 GET 命令字符串
4. conn_parse_cmd → 解析出 GET 和 key
5. conn_write → 写回 value 或 NOT_FOUND
6. conn_new_cmd(准备下一条命令)

总结

conn_statememcached 网络处理层的核心枚举,配合 drive_machine() 构成高性能状态机。每一个状态都只负责一小段逻辑,通过事件驱动和状态切换高效调度连接资源。

建议深入阅读 memcached.c 中的 drive_machine(),配合 gdb 或 printf 日志观察状态切换过程,有助于掌握服务端异步网络编程的核心模型。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐