告别多进程/多线程!基于 select 打造单线程高并发服务器

📅 发布时间:2026/7/9 20:58:08 👁️ 浏览次数:
告别多进程/多线程!基于 select 打造单线程高并发服务器
在传统的并发模型中,每来一个连接就分配一个独立执行流(线程/进程),这不仅会消耗大量内存,频繁的上下文切换也会拖垮 CPU。而select多路转接模型的核心魅力在于:单线程通过委托内核检测多个文件描述符的状态变化,从而实现高效的并发通信。下面,我们将把课堂笔记中的理论一步步转化为可执行的工业级代码。一、 核心原理解析与代码骨架搭建构建一个select服务器,核心分为四大战役:设置监听、初始化检测集合、循环委托内核检测、处理就绪事件。1. 基础环境与设置监听与普通服务器一样,我们需要先创建一个监听套接字(lfd),并将其绑定到指定端口(笔记中约定为8989端口),最后设置监听队列长度为 128。注意:每一步系统调用都必须配合perror()进行严格的错误返回检查。2. fd_set 集合的“双重替身”机制这是select编程最容易踩坑的地方!我们必须定义两个fd_set集合:reads集合:作为大本营,记录所有我们真正想要监控的文件描述符(原始数据)。tmp集合:作为替身,每次调用select时传给内核。因为内核会修改传入的集合(把没事件发生的 FD 踢出去),所以必须用tmp挨这“一刀”,从而保护reads的完整性。3. nfds:内核遍历的加速器变量nfds用于记录当前集合中最大的文件描述符值。调用select时,传入nfds + 1,告诉内核:“你只需要遍历到这里就可以了,后面的不用管”,极大地提高了检测效率。二、 完整代码实战:单线程通信服务器结合笔记中的逻辑分支,我们将连接处理(accept)和数据通信(recv)完美融合到一起。#includestdio.h#includestdlib.h#includestring.h#includeunistd.h#includearpa/inet.h#includesys/select.hintmain(){// 1. 创建监听套接字 lfdintlfd=socket(AF_INET,SOCK_STREAM,0);if(lfd==-1){perror("socket error");exit(1);}// 设置端口复用(防止重启时端口被占用)intopt=1;setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,opt,sizeof(opt));// 2. 绑定端口 8989structsockad