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日

相关文章

  • 论文笔记之:Conditional Generative Adversarial Nets

    论文笔记之: Conditional Generative Adversarial Nets 简介 Conditional Generative Adversarial Nets,简称CGAN,是一种生成对抗网络(GAN)的扩展。相对于传统的GAN,CGAN在输入噪声向量的基础上,额外输入了条件信息,使得生成的结果能够针对条件信息的不同而变化,具有更好的灵活…

    其他 2023年3月28日
    00
  • Asp.net第三方控件ComboBox组合框介绍

    Asp.net第三方控件ComboBox组合框介绍 介绍 ComboBox组合框是一种常见的控件,可以用于设置多个选项,并且只能选择其中一个选项。在Asp.net中,有可以使用第三方控件实现ComboBox组合框的功能。 安装第三方控件 在Asp.net中使用第三方控件前,需要先安装控件包。以Telerik控件为例,按照以下步骤安装: 找到Telerik官网…

    other 2023年6月27日
    00
  • Xshell怎么开启布局管理?Xshell开启布局管理教程

    Xshell怎么开启布局管理 Xshell是一款功能强大的终端模拟器,可以通过开启布局管理来实现多个终端窗口的同时显示和管理。下面是详细的攻略: 步骤一:打开Xshell 首先,双击打开Xshell应用程序。 步骤二:创建新会话 在Xshell的菜单栏中,点击\”文件\”,然后选择\”新建\”,再选择\”会话\”。这将打开一个新的会话窗口。 步骤三:开启布局…

    other 2023年9月5日
    00
  • openssl下载安装

    以下是关于如何下载安装OpenSSL的完整攻略: 1. 下载OpenSSL 可以从OpenSSL官方网站(https://www.openssl.org/)下载OpenSSL。在下载页面中,可以选择下载最新版本或旧版本的OpenSSL。选择适合自己的版本后,可以下载对应的压缩包。 例如,下载OpenSSL 1.1.1版本的压缩包,可以使用以下命令: wget…

    other 2023年5月8日
    00
  • 恐怖黎明图像引擎初始化失败问题解决步骤

    恐怖黎明图像引擎初始化失败问题解决步骤 如果你在运行恐怖黎明游戏时遇到了“图像引擎初始化失败”的问题,不要担心,下面是解决此问题的步骤。 步骤一:检查硬件和驱动 首先,你需要确保你的计算机硬件能够支持该游戏,包括CPU、内存和显卡。 其次,你需要检查显卡驱动程序是否已经更新到最新版本。通过更新显卡驱动程序可以解决一些因为显卡驱动问题导致的游戏无法正常运行的问…

    other 2023年6月20日
    00
  • 原生JS实现图片懒加载(lazyload)实例

    下面就来详细讲解原生JS实现图片懒加载(lazyload)实例的完整攻略。 什么是懒加载(lazyload) 懒加载(也称为延迟加载)是一种在网页上优化图片加载的技术,它可以减少网页的初次加载时间,提高用户体验。懒加载的原理是在页面初始加载时,只加载可视区域内的图片,当用户滑动页面时,再加载其他区域的图片,这样可以避免一次性请求大量的图片资源,减少页面的下载…

    other 2023年6月25日
    00
  • JavaScript进阶(一)变量声明提升实例分析

    JavaScript进阶(一)变量声明提升实例分析 在JavaScript中,变量声明提升是一种特性,它允许在变量声明之前就可以使用这些变量。这意味着,无论变量声明在代码的哪个位置,它们都会被提升到作用域的顶部。 1. 变量声明提升的基本概念 变量声明提升是JavaScript引擎在代码执行之前将变量声明移动到作用域顶部的过程。这意味着,无论变量声明在代码的…

    other 2023年8月8日
    00
  • Android Widget 桌面组件开发介绍

    Android Widget 桌面组件开发介绍 什么是 Android Widget? Android Widget 是一种可以在 Android 设备的桌面上显示的小组件。它们可以提供实时信息、快捷方式和交互功能,使用户能够直接在桌面上执行特定任务,而无需打开应用程序。 开发 Android Widget 的步骤 步骤 1:创建 Widget 的布局文件 …

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