首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

linux epoll例程

epoll 是 Linux 下用于处理大量文件描述符(比如网络连接)的高效 I/O 事件通知机制。它是 selectpoll 的替代品,特别适用于高并发场景。

基础概念

epoll 提供了三种系统调用:

  1. epoll_create: 创建一个 epoll 实例。
  2. epoll_ctl: 向 epoll 实例中添加、修改或删除要监控的文件描述符。
  3. epoll_wait: 等待 epoll 实例中的文件描述符就绪,并返回就绪的文件描述符列表。

优势

  • 效率高epoll 使用红黑树管理文件描述符,添加、删除和查找的时间复杂度都是 O(log n)。同时,它使用事件驱动的方式,只有当文件描述符就绪时才会通知应用程序,避免了轮询的开销。
  • 扩展性好epoll 没有最大并发连接的限制,只受限于系统内存大小。
  • 支持边缘触发和水平触发:边缘触发(ET)只在状态变更时通知,可能更适合高负载场景;水平触发(LT)则是在文件描述符就绪时持续通知,更容易使用。

应用场景

epoll 常用于构建高性能的网络服务器,如 Web 服务器、聊天服务器等,特别是在需要处理大量并发连接的场景下。

示例代码

以下是一个简单的 epoll 服务器示例,使用边缘触发模式:

代码语言:txt
复制
#include <sys/epoll.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_EVENTS 10
#define PORT 8080

int set_nonblocking(int fd) {
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) return -1;
    flags |= O_NONBLOCK;
    return fcntl(fd, F_SETFL, flags);
}

int main() {
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd == -1) perror("socket");

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);

    if (bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) perror("bind");

    if (listen(listen_fd, SOMAXCONN) == -1) perror("listen");

    int epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) perror("epoll_create1");

    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = listen_fd;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &event) == -1) perror("epoll_ctl");

    struct epoll_event events[MAX_EVENTS];

    while (1) {
        int n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (n == -1) perror("epoll_wait");

        for (int i = 0; i < n; i++) {
            if (events[i].data.fd == listen_fd) {
                while (1) {
                    struct sockaddr_in client_addr;
                    socklen_t client_len = sizeof(client_addr);
                    int conn_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_len);
                    if (conn_fd == -1) {
                        if (errno == EAGAIN || errno == EWOULDBLOCK) break;
                        else perror("accept");
                        continue;
                    }
                    set_nonblocking(conn_fd);
                    event.events = EPOLLIN | EPOLLET;
                    event.data.fd = conn_fd;
                    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, &event) == -1) perror("epoll_ctl");
                }
            } else {
                char buf[1024];
                int conn_fd = events[i].data.fd;
                while (1) {
                    ssize_t count = read(conn_fd, buf, sizeof(buf));
                    if (count == -1) {
                        if (errno == EAGAIN || errno == EWOULDBLOCK) break;
                        else perror("read");
                        close(conn_fd);
                        break;
                    } else if (count == 0) {
                        close(conn_fd);
                        break;
                    }
                    write(conn_fd, buf, count);  // Echo back
                }
            }
        }
    }

    close(listen_fd);
    close(epoll_fd);
    return 0;
}

这个示例代码创建了一个简单的回声服务器,使用 epoll 来处理并发连接。注意,在实际应用中,你可能需要添加更多的错误处理和资源管理代码。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

从linux源码看epoll

前言 在linux的高性能网络编程中,绕不开的就是epoll。和select、poll等系统调用相比,epoll在需要监视大量文件描述符并且其中只有少数活跃的时候,表现出无可比拟的优势。...本文就是笔者在探究epoll源码过程中,对kernel将就绪描述符添加到epoll并唤醒对应进程的一次源码分析(基于linux-2.6.32内核版本)。...由于linux的系统调用是通过(SYSCALL_DEFINE1,SYSCALL_DEFINE2......SYSCALL_DEFINE6)定义的,那么sys_epoll_create1对应的源码即是SYSCALL_DEFINE...的软中断机制调用net_rx_action,如下图所示: 注:上图来自PLKA(Linux内核架构>>) step2: 紧接着跟踪next_rx_action next_rx_action...总结 epoll作为linux下非常优秀的事件触发机制得到了广泛的运用。其源码还是比较复杂的,本文只是阐述了epoll读写事件的触发机制,探究linux kernel源码的过程非常快乐_。

2.3K20
  • Linux epoll 源码分析 3

    在上一篇文章 Linux epoll 源码分析 2 中,我们分析了 epoll_ctl 的 ep_insert 方法,在这里我们继续看下 ep_remove 和 ep_modify 方法。...return 0; } 再看下ep_modify 方法 static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_event...return 0; } 该方法的逻辑和ep_insert方法里的逻辑比较像,它先覆盖epitem中epoll_event的旧值,然后检查该文件当前已经就绪的事件,如果这些事件中有我们感兴趣的事件,则把epitem...放到eventpoll的rdllist队列中,最后通知因调用epoll_wait堵塞的线程,它们可以继续执行了。...至此,epoll的所有逻辑都已讲完。 有关tcp在何种情况下,会通知给epoll何种事件,我们会在其他文章中详细讲解。

    1.8K30

    从linux源码看epoll

    从linux源码看epoll 前言 在linux的高性能网络编程中,绕不开的就是epoll。...本文就是笔者在探究epoll源码过程中,对kernel将就绪描述符添加到epoll并唤醒对应进程的一次源码分析(基于linux-2.6.32内核版本)。...由于linux的系统调用是通过(SYSCALL_DEFINE1,SYSCALL_DEFINE2......SYSCALL_DEFINE6)定义的,那么sys_epoll_create1对应的源码即是SYSCALL_DEFINE...注:上图来自PLKA(Linux内核架构>>) step2: 紧接着跟踪next_rx_action next_rx_action |-process_backlog .........总结 epoll作为linux下非常优秀的事件触发机制得到了广泛的运用。其源码还是比较复杂的,本文只是阐述了epoll读写事件的触发机制,探究linux kernel源码的过程非常快乐^_^。

    5.2K41

    深入理解 Linux 的 epoll 机制

    在 Linux 系统之中有一个核心武器:epoll 池,在高并发的,高吞吐的 IO 系统中常常见到 epoll 的身影。...高效的原理 Linux 下,epoll 一直被吹爆,作为高并发 IO 实现的秘密武器。...Linux 内核对于 epoll 池的内部实现就是用红黑树的结构体来管理这些注册进程来的句柄 fd。...管理; socket fd,eventfd,timerfd 这些实现了 poll 调用的可以放到 epoll 池进行管理; 其实,在 Linux 的模块划分中,eventfd,timerfd,epoll...还是那句话,Linux 内核帮你包圆了。今天并没有罗列太多源码实现,以很小的思考点为题展开,简单讲了一些 epoll 的思考,以后有机会可以分享下异步IO( aio )和 epoll 能产生什么火花?

    8K125

    如何在Python中使用Linux epoll

    原文链接:http://scotdoyle.com/python-epoll-howto.html 如何在Python中使用Linux epoll 内容 介绍...阻塞套接字编程示例 异步套接字和Linux epoll的好处 epoll的异步套接字编程示例 性能考量 源代码 介绍 从2.6版开始,Python包含用于访问Linux epoll库的API。...Linux有许多用于管理异步套接字的机制,其中三种由Python select,poll和epoll API公开。...epoll比poll更好,因为它不需要操作系统每次在Python程序查询时都检查所有套接字中是否有感兴趣的事件。 相反,Linux会跟踪这些事件的发生情况,并在由Python查询时返回一个列表。...例如,当使用ab对具有100个并发HTTP 1.0客户端的这些示例程序执行负载测试时,任何小于50的积压值通常会导致性能下降。

    3.2K10

    【Linux】高级IO --- 多路转接,select,poll,epoll

    而此时走过来一个李四,李四这名少年也很喜欢钓鱼,但李四和张三不一样,李四左口袋装着《Linux高性能服务器编程》,右口袋装着一本《算法导论》,左手拿手机,右手拿了一根鱼竿,李四拿了钓鱼凳坐下之后,李四就开始钓鱼了...在这里额外补充一下,linux命令行中表示输入结束的快捷键是ctrl+d,当此热键被用户按下后,代表0号文件描述符写端关闭,此时读端会读到0,read会返回0值,此时进程除了输出提示信息"read file...虽然说epoll是作了改进的poll,但在接口的使用和底层实现上,epoll和poll天差地别,在linux内核2.5.44版本时,就引入了epoll接口,而现在主流的linux内核版本已经是3点几了。...结构体,所以epoll_create创建epoll模型成功后,会返回一个文件描述符,而epoll_create的size参数早在内核版本2.6以后就已经被忽略了,在早期的linux内核版本中,该参数指定的是...select优点: (1)能够同时监听多个文件描述符,使得一个进程或线程能够同时管理多个IO操作,提升IO的效率 (2)select 是一个跨平台的系统调用,几乎在所有主流操作系统上都得到支持,包括 Linux

    36830

    linux epoll 开发指南-【ffrpc源码解析】

    摘要 关于epoll的问题很早就像写文章讲讲自己的看法,但是由于ffrpc一直没有完工,所以也就拖下来了。Epoll主要在服务器编程中使用,本文主要探讨服务器程序中epoll的使用技巧。...Epoll 的io模型 Epoll是为异步io操作而设计的,epoll中IO事件被分为read事件和write事件,如果大家对于linux的驱动模块或者linux io 模型有接触的话,就会理解起来更容易...Linux中IO操作被抽象为read、write、close、ctrl几个操作,所以epoll只提供read、write、error事件,是和linux的io模型是统一的。  ...为什么要了解epoll的io模型呢,本文认为,某些情况下epoll操作的代码的复杂性是由于代码中的模型(或者类设计)与epoll io模型不匹配造成的。...man epoll中的FAQ告诉我们,当socket被close掉后,其自动从epoll中删除。

    1.5K50

    Linux中epoll IO多路复用机制

    epoll简介 epoll 是Linux内核中的一种可扩展IO事件处理机制,最早在 Linux 2.5.44内核中引入,可被用于代替POSIX select 和 poll 系统调用,并且在具有大量应用程序请求时能够获得较好的性能...当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close() 关闭,否则可能导致fd被耗尽...[cpp] plaincopyint epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); epoll的事件注册函数,第一个参数是...epoll_create() 的返回值,第二个参数表示动作,使用如下三个宏来表示: [cpp] EPOLL_CTL_ADD //注册新的fd到epfd中; EPOLL_CTL_MOD...select支持的句柄数是有限制的, 同时只支持1024个,这个是句柄集合限制的,如果超过这个限制,很可能导致溢出,而且非常不容易发现问题, TAF就出现过这个问题, 调试了n天,才发现:)当然可以通过修改linux

    1.5K90
    领券