epool介绍

epoll介绍

epoll是Linux内核提供的一种高效的I/O多路复用机制,用于处理大量的并发连接。它可以监视多个文件描述符,当其中任何一个文件描述符就绪时,就通知应用程序进行处理。ep是Linux内核2.6版本引入的,相比于select和poll,它具有更好的性能和可伸缩性。

epoll的优点

  • 支持较大的并发连接数,可以处理数百万个连接。
  • 监视的文件描述数量不受限制,可以支持数百万个文件描述符。
  • 支持水平触发和边缘触发两种模式。
  • 支持EPOLLONESHOT选项,可以保证每个文件描述符只被一个程处理。
  • 支持EPOLLEXCLUSIVE选项,可以保证每个文件描述符只被一个进程处理。

epoll的工作原理

epoll使用一个事件表来存储文件描述符和事件。当调用epoll_wait()函数时,内核会检查事件表中的文件描述符,如果有文件描述符就绪,就将其加入到就绪链表中。epoll_wait()函数会返回就绪链表中的文件描述符数量,并将就绪链表中的文件描述符复制到用户空间中。应用程序可以使用这些文件描述符进行读写操作。

示例一:使用epoll实现高并发服务器

#include <sysepoll.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define MAX_EVENTS 1024
#define BUF_SIZE 1024

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

int main(int argc, char *argv[]) {
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(8080);

    if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    if (listen(listen_fd, SOMAXCONN) == -1) {
       ("listen");
        exit(EXIT_FAILURE);
    }

    int epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) {
        perror("epoll_create1");
        exit(EXIT_FAILURE);
    }

    struct epoll_event event;
    event.data.fd = listen_fd;
    event.events = EPOLLIN | EPOLLET;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &event) == -1) {
        perror("epoll_ctl");
        exit(EXIT_FAILURE    }

    struct epoll_event *events = (struct epoll_event *)calloc(MAX_EVENTS, sizeof(struct epoll_event));

    while (1) {
        int n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        for (int i = 0; i <; i++) {
            if (events[i].data.fd == listen_fd) {
                int conn_fd = accept(listen_fd, NULL, NULL);
                if (conn_fd == -1) {
                    perror("accept");
                    continue;
                }
                setnonblocking(conn_fd);
                event.data.fd = conn_fd;
                event.events = EPOLLIN | EPOLLET;
                if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, &event) == -1) {
                    perror("epoll_ctl");
                    exit(EXIT_FAILURE);
                }
            } else {
                int conn_fd = events[i].data.fd;
                char buf[BUF_SIZE];
                memset(buf, 0, sizeof(buf));
                int n = read(conn_fd, buf, sizeof(buf));
                if (n == -1) {
                    if (errno == ECONNRESET) {
                        close(conn_fd);
                        epoll_ctl(epoll_fd, EPOLL_CTL_DEL, conn_fd, NULL);
                    } else {
                        perror("read");
                    }
                } else if (n == 0) {
                    close(conn_fd);
                    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, conn_fd, NULL);
                } else {
                    printf("recv: %s\n", buf);
                    write(conn_fd, buf, n);
                }
            }
        }
    }

    free(events);
    close(epoll_fd);
    close(listen_fd);

    return 0;
}

在这个示例中,我们使用epoll实现了一个高并发的服务器。首先创建一个socket并绑定到指定的端口,然后使用epoll_create1()函数创建一个epoll实例。将监听socket添加到epoll实例中,然后使用epoll()函数等待事件。当有新的连接到来时,将连接socket添加到epoll实例中。当连接socket可读时,读取数据并将其发送回客户端。

示例二:使用epoll实现高性能的HTTP服务器

#include <sys/epoll.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define MAX_EVENTS 1024
#define BUF_SIZE 1024

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

int main(int argc, char *argv[]) {
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(8080);

    if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    if (listen(listen_fd, SOMAXCONN) == -1) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    int epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) {
        perror("epoll_create1");
        exit(EXIT_FAILURE);
    }

    struct epoll_event event;
    event.data.fd = listen_fd;
    event.events = EPOLLIN | EPOLLET;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &event) == -1) {
        perror("epoll_ctl");
        exit(EXIT_FAILURE);
    }

    struct epoll_event *events = (struct epoll_event *)calloc(MAX_EVENTS, sizeof(struct epoll_event));

    while (1) {
        int n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        for (int i = 0; i < n; i++) {
            if (events[i].data.fd == listen_fd) {
                int conn_fd = accept(listen_fd, NULL, NULL);
                if (conn_fd == -1) {
                    perror("accept");
                    continue;
                }
                setnonblocking(conn_fd);
                event.data.fd = conn_fd;
                event.events = EPOLLIN | EPOLLET;
                if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, &event) == -1) {
                    perror("epoll_ctl");
                    exit(EXIT_FAILURE);
                }
            } else {
                int conn_fd = events[i].data.fd;
                char buf[BUF_SIZE];
                memset(buf, 0, sizeof(buf));
                int n = read(conn_fd, buf, sizeof(buf));
                if (n == -1) {
                    if (errno == ECONNRESET) {
                        close(conn_fd);
                        epoll_ctl(epoll_fd, EPOLL_CTL_DEL, conn_fd, NULL);
                    } else {
                        perror("read");
                    }
                } else if (n == 0) {
                    close(conn_fd);
                    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, conn_fd, NULL);
                } else {
                    char response[BUF_SIZE];
                    memset(response, 0, sizeof(response));
                    sprintf(response, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s", n, buf);
                    write(conn_fd, response, strlen(response));
                }
            }
        }
    }

    free(events);
    close(epoll_fd);
    close(listen_fd);

    return 0;
}

在这个示例中,我们使用epoll实现了一个高性能的HTTP服务器。与前面的示例类似,首先创建一个socket并绑定到指定的端口,然后使用epoll_create1()函数创建一个epoll实例。将监听socket添加到epoll实例中,然后使用epoll_wait()函数等待事件。当有新的连接到来时,将连接socket添加到epoll实例中。当连接socket可读时,读取数据并将其作为HTTP响应发送回客户端。

总之,epoll是Linux内核提供的一种高效的I/O多路复用机制,用于处理大量的并发连接。可以使用epoll实现高并发服务器或高性能的HTTP服务器。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:epool介绍 - Python技术站

(0)
上一篇 2023年5月8日
下一篇 2023年5月8日

相关文章

  • PHP cURL初始化和执行方法入门级代码

    下面我将详细讲解“PHP cURL初始化和执行方法入门级代码”的完整攻略。 什么是cURL? cURL是用于传输HTTP、HTTPS、FTP、IMAP等协议的工具和库。同时也是一些常用命令行工具(如wget、aria2等)的底层库。cURL具有代码规范的易用性,支持cookie、HTTP认证、代理等操作,被广泛应用于web开发领域。 cURL的初始化方法 在…

    other 2023年6月20日
    00
  • intel的mkl是可以用来训练的—的实验也提到了训练

    Intel的MKL是可以用来训练的——的实验也提到了训练 在深度学习中,训练模型是一个非常耗费计算资源的过程。因此,针对不同的硬件和软件环境,选取一个高效的训练工具非常关键。而Intel Math Kernel Library (MKL)作为一个高效的数学库,在训练中也扮演着重要的角色。 实验也证实了这一点。在“ImageNet Large Scale Vi…

    其他 2023年3月28日
    00
  • Win10出现自定义任务栏快捷图标丢失等异常情况怎么解决?

    Win10出现自定义任务栏快捷图标丢失等异常情况的解决攻略 自定义任务栏快捷图标丢失、无法删除、无法打开等异常情况是 Windows 10 操作系统中常见的问题,下面介绍一些可能的解决方法。 方法一:重置任务栏 按下 Ctrl + Shift + Esc 组合键打开任务管理器。 在“进程”选项卡中找到并结束名为 “Windows Explorer” 的进程。…

    other 2023年6月25日
    00
  • dos/bat中获取用户输入内容的代码(保存到文件中)

    当我们需要从用户那里获取输入数据时,可以通过在 DOS/BAT 脚本中使用 set /p 命令来实现。set /p 命令的使用格式如下: set /p variable=prompt text 其中,variable 是用户输入数据后赋值的变量;prompt text 是提示用户输入的文本。 获取用户输入数据并保存到文件的方式,可以使用 echo 命令将 s…

    other 2023年6月26日
    00
  • python单向循环链表原理与实现方法示例

    Python单向循环链表原理与实现方法示例 1. 什么是单向循环链表 单向循环链表是指链表的最后一个节点指向链表的第一个节点,形成一个环。单向循环链表可以实现数据的循环使用和遍历以及其他链表的基本操作。 2. 单向循环链表的实现方法 单向循环链表的实现方法是:有一个head指针指向链表的第一个节点,而链表的最后一个节点的next指针指向head,形成一个环。…

    other 2023年6月27日
    00
  • [下载]苹果iOS9.1 Beta5固件下载地址大全

    [下载]苹果iOS9.1 Beta5固件下载地址大全攻略 苹果iOS9.1 Beta5固件是苹果公司发布的一款测试版本固件,本攻略将详细介绍如何下载该固件以及提供下载地址大全。请按照以下步骤进行操作: 步骤一:准备工作 在开始下载iOS9.1 Beta5固件之前,请确保您已经完成以下准备工作: 确认您的设备兼容性:iOS9.1 Beta5固件可能只适用于特定…

    other 2023年8月4日
    00
  • QT利用QProcess获取计算机硬件信息

    下面是“QT利用QProcess获取计算机硬件信息”的完整攻略: 1.引言 我们在进行软件的开发时,有时需要获取计算机硬件信息。这时候我们可以使用QT框架提供的QProcess类来执行系统命令,获取相关信息。 2.步骤 步骤一:创建QProcess对象 我们需要创建一个QProcess对象,来执行相应的系统命令。 QProcess* process = ne…

    other 2023年6月26日
    00
  • Windows 11的这19个新功能,你都知道吗?

    Windows 11的这19个新功能,你都知道吗? Windows 11是微软最新发布的操作系统,带来了许多令人兴奋的新功能。在这篇攻略中,我们将详细介绍这19个新功能,并提供两个示例说明。 1. 全新的开始菜单和任务栏 Windows 11带来了全新的开始菜单和任务栏设计。开始菜单现在位于屏幕中间,具有现代化的外观和感觉。任务栏也进行了重新设计,使其更加简…

    other 2023年9月6日
    00
合作推广
合作推广
分享本页
返回顶部