• 网络编程(五)——poll和epoll


    poll原理:

    
    当调用poll函数时,内核会遍历所有需要监测的文件描述符,并将其添加到一个等待队列中。
    
    当有事件发生时,内核会遍历等待队列上的文件描述符,检查是否有事件发生。
    
    当有事件发生的文件描述符被找到时,内核会通过修改poll函数的返回值,告知应用程序哪些文件描述符有事件发生。
    
    应用程序通过遍历poll函数返回的结构体数组,找到有事件发生的文件描述符,并进行相应的处理。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    epoll原理:

    当调用epoll_create函数时,内核会创建一个epoll对象,并返回一个文件描述符,该文件描述符用于对epoll对象进行操作。
    
    当调用epoll_ctl函数时,我们可以将需要监测的文件描述符添加到epoll对象中。
    
    当调用epoll_wait函数时,内核会等待事件发生,并将发生事件的文件描述符添加到一个就绪队列中。
    
    应用程序通过调用epoll_wait函数获取就绪队列上的事件,利用返回的文件描述符进行相应的处理。
    
    与poll不同,为了避免遍历所有需要监测的文件描述符,epoll采用事件驱动的方式,只需要遍历就绪队列上的文件描述符即可。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    epoll相较于poll的优势主要体现在:

    CPU效率:epoll使用事件驱动的方式,只有在有事件到达时才会遍历,节省了CPU资源。而poll需要遍历所有需要监测的文件描述符。
    
    内存复制:epoll返回文件描述符而不是复制数据,避免了poll每次返回数据时需要进行内存复制的开销。
    
    文件描述符数量:epoll支持打开的文件描述符数量更大,不会随着文件描述符数目的增长而降低效率。
    
    
    总的来说,poll和epoll都是为了实现I/O多路复用提供的机制,但epoll相对于poll在性能上有更好的表现。因此,在高性能的网络编程中,epoll被广泛使用。
    
    poll和epoll是Linux系统中的两种I/O多路复用机制。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    poll结构体的定义

    struct pollfd {
        int fd;           // 文件描述符
        short events;     // 监控的事件
        short revents;    // 实际发生的事件
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    poll的使用示例:

    #include 
    #include 
    #include 
    #include 
    
    #define TIMEOUT_MS 5000
    
    int main() {
        struct pollfd fds;
        int ret;
    
        fds.fd = STDIN_FILENO;    // 监控标准输入
        fds.events = POLLIN;      // 监控可读事件
    
        ret = poll(&fds, 1, TIMEOUT_MS);
        if (ret == -1) {
            perror("poll");
            return 1;
        }
    
        if (ret == 0) {
            printf("Timeout\n");
        }
    
        if (fds.revents & POLLIN) {
            printf("Data is available now.\n");
        }
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    epoll结构体的定义:

    struct epoll_event {
        __uint32_t events;  // epoll事件类型
        epoll_data_t data;  // 用户数据
    };
    
    typedef union epoll_data {
        void *ptr;
        int fd;
        __uint32_t u32;
        __uint64_t u64;
    } epoll_data_t;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    epoll的使用示例:

    #include 
    #include 
    #include 
    #include 
    
    #define MAX_EVENTS 5
    
    int main() {
        struct epoll_event event, events[MAX_EVENTS];
        int epoll_fd, event_count;
    
        // 创建epoll实例
        epoll_fd = epoll_create1(0);
        if (epoll_fd == -1) {
            perror("epoll_create1");
            return 1;
        }
    
        // 监听标准输入可读事件
        event.events = EPOLLIN;
        event.data.fd = STDIN_FILENO;
    
        // 将标准输入添加到epoll监控列表
        if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, STDIN_FILENO, &event) == -1) {
            perror("epoll_ctl");
            return 1;
        }
    
        while (1) {
            event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
            if (event_count == -1) {
                perror("epoll_wait");
                return 1;
            }
    
            printf("Events occurred: %d\n", event_count);
    
            for (int i = 0; i < event_count; i++) {
                if (events[i].data.fd == STDIN_FILENO) {
                    printf("Data is available now.\n");
                    char buf[256];
                    fgets(buf, sizeof(buf), stdin);
                    printf("Read: %s", buf);
                }
            }
        }
    
        return 0;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
  • 相关阅读:
    SQL注入攻击分为几类?如何防御?
    李宏毅机器学习第一课(结尾附作业模型详细分析)
    Springboot整合JPA多数据源(Oracle+Mysql)
    【C++】:类和对象(中)之拷贝构造函数+赋值运算符重载
    Linux篇【5】:Linux 进程概念(三)
    2023 年如何学习编程
    BufferedReader和BufferedWriter的实现原理
    Web3知识科普:什么是多签钱包?
    [linux] 查看进程PID以及进程详细信息
    ffmpeg Operation not permitted
  • 原文地址:https://blog.csdn.net/qq_59566583/article/details/132791069