在使用 Reactor 网络模型与 Redis 交互时,当连接 Redis 返回 -1(通常表示连接未立即完成,例如非阻塞模式下连接尝试返回 EINPROGRESS),此时需要将套接字放入 epoll 监听并注册写事件(EPOLLOUT),原因如下:
1. 非阻塞连接的特性
- 在非阻塞模式下调用
connect()时,如果连接不能立即建立(例如 TCP 三次握手需要时间),系统会返回-1并将错误码设为EINPROGRESS,表示连接正在后台进行。 - 此时需要监听写事件,因为当连接成功建立(或失败)时,内核会通过写就绪(EPOLLOUT)通知应用程序(epoll 会报告该套接字可写)。
2. 为什么是写事件(EPOLLOUT)?
- TCP 协议规定:连接建立成功后,套接字会变为可写状态(即发送缓冲区可用)。因此,通过监听写事件可以检测连接是否完成。
- 如果连接失败(如被拒绝或超时),套接字会同时触发读和写事件(EPOLLIN | EPOLLOUT),并且可以通过
getsockopt(fd, SOL_SOCKET, SO_ERROR, ...)获取错误码。
3. 具体操作步骤
- 设置套接字为非阻塞模式,调用
connect()返回-1(错误码为EINPROGRESS)。 - 将该套接字添加到 epoll,监听 EPOLLOUT 事件(等待连接完成)。
- 当 epoll 触发 EPOLLOUT 事件时:
- 检查连接状态:调用 `getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len)`: - 如果 `error` 为 `0`,表示连接成功。 - 否则连接失败(需处理错误)。 - 连接成功后,移除对 EPOLLOUT 的监听(避免后续不必要的可写事件触发),并根据业务需求注册读事件(EPOLLIN)或其他事件。
❗注意事项
- 避免忙等待:非阻塞连接通过 epoll 监听写事件实现异步,避免了轮询检查连接状态。
- 超时处理:可能需要同时设置定时器(例如通过 epoll_timeout 或额外线程),防止连接长时间未完成或失败。
- 错误处理:触发 EPOLLOUT 后必须检查 SO_ERROR,因为即使可写也不一定代表连接成功(可能是连接失败后的可写状态)。
✅总结
注册写事件是为了异步检测非阻塞连接的完成状态。这是 Reactor 模型中处理非阻塞连接的通用做法,适用于 Redis、MySQL 或其他基于 TCP 的后端服务交互。
内容由零声教学AI助手提供,问题来源于学员提问




