Hello epoll!
一、先搞清楚 fd 是个啥
在 Linux 里,有句话叫:“一切皆文件”。
什么意思呢?
就是不管是硬盘文件、键盘、管道、socket 网络连接……
在系统眼里都是“文件”,都有一个整数编号,这个编号就叫 fd(文件描述符)。
比如我打开一个文件:
int fd = open("test.txt", O_RDONLY);
这个 fd 就是一个整数,代表系统里那个文件的“身份证号”。
再比如我创建一个网络连接:
int sock = socket(AF_INET, SOCK_STREAM, 0);
它也是返回一个 fd,说明 socket 其实也被当作“文件”来管理的。
二、socket 是怎么回事?
sokcet() 是一个系统调用,用来创建网络通信通道。
你可以把它理解成“买了一部电话 ”。
服务端拿到电话后,还要:
bind()   // 绑定电话号码(IP + 端口)
listen() // 等待别人打进来
accept() // 接听电话
客户端则直接:
connect() // 主动打电话给服务端
这俩电话一连上,就能通过 send() 和 recv() 传消息了。
三、为什么会有 epoll?
问题来了,如果你是服务器,有 1000 个客户端连着你,
你得知道谁发消息了、谁没发,对吧?
那以前人是怎么干的?
就是不停去“问”每个 socket:
“你有消息吗?”
“你呢?”
“那你呢?”
这就是 select() 或 poll() 的做法。
问题是:每次都要遍历所有连接,非常慢。
于是 Linux 就出了一个新机制——epoll。
它的意思其实就是 “Event Poll(事件轮询)”,
但是它是内核来帮你盯着所有 socket,
有事才通知你,没事你就休息。
四、epoll 就像秘书一样
你是老板,公司有 100 个电话线。
你懒得一个个去听,就雇了个秘书。
你告诉她:
“帮我盯着所有电话,有哪个响了就叫我。”
这就是 epoll。
你用 epoll_ctl() 告诉它要监听哪些电话(socket),
然后在 epoll_wait() 那里等着,
有哪个 socket 有消息,它就会回来告诉你:
“老板,4 号电话有人说话啦!”
五、epoll 的三个主要函数
| 函数 | 作用 | 
|---|---|
epoll_create1() | 创建 epoll 实例(就像雇秘书) | 
epoll_ctl() | 注册你要监听的 fd(告诉秘书看哪些电话) | 
epoll_wait() | 等待事件发生(秘书喊你) | 
代码流程是这样:
int epfd = epoll_create1(0);  // 创建 epoll
epoll_event ev{}, events[10];ev.events = EPOLLIN; // 关心“可读事件”
ev.data.fd = sock_fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, sock_fd, &ev); // 告诉 epoll 监听这个 fdint n = epoll_wait(epfd, events, 10, -1); // 等待事件发生
for (int i = 0; i < n; ++i) {std::cout << "fd " << events[i].data.fd << " is ready\n";
}
六、我自己写的小项目
我做了一个小 demo,
用 epoll 同时监听一个文件和一个 socket:
int file_fd = open("test.txt", O_RDONLY);
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);int epfd = epoll_create1(0);
epoll_event ev{}, events[10];// 把文件加进去(其实会报错)
ev.events = EPOLLIN;
ev.data.fd = file_fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, file_fd, &ev);// 把 socket 加进去
ev.data.fd = sock_fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, sock_fd, &ev);std::cout << "Waiting for events...\n";
int n = epoll_wait(epfd, events, 10, -1);
for (int i = 0; i < n; ++i)std::cout << "fd " << events[i].data.fd << " is ready for read.\n";
运行结果:
epoll_ctl add failed: Operation not permitted
[Epoll] Added fd=4 to epoll
[Epoll] Waiting for events...
[Epoll] Event count: 1→ fd 4 is ready for read.
原因:
文件不能用 epoll 监听(因为它永远是“可读”的,没有事件);
socket 可以,epoll 会在状态变化时通知你;
所以整个流程是完全通的 。
七、为什么 epoll 快
select()、poll() 是遍历所有连接(O(n))。
epoll 是内核帮你维护“就绪列表”,
有事就放进队列里,你直接拿结果(O(1))。
不管你有 10 个连接还是 1 万个连接,
epoll_wait() 只返回那些真的有事件的 fd,
这就是它能支撑高并发的原因。
八、学完今天的收获
| 学到的东西 | 说明 | 
|---|---|
| fd | 系统用整数编号管理文件和 socket | 
| socket | 创建网络通信端点 | 
| epoll | 内核级事件通知系统 | 
| 文件 I/O vs 网络 I/O | epoll 只适用于会产生事件的 fd,比如 socket | 
