epoll实现 IO复用

news2024/11/24 6:48:33

1、epoll实现 IO复用

epoll的提出--》它所支持的文件描述符上限是系统可以最大打开的文件的数目;eg:1GB机器上,这个上限10万个左右。 每个fd上面有callback(回调函数)函数,只有活跃的fd才有主动调用callback,不需要轮询。 注意: Epoll处理高并发,百万级,不关心底层怎样实现,只需要会调用就可以。

函数接口

#include <sys/epoll.h>
int epoll_create(int size); 
功能:创建红黑树根节点
 参数:size:不作为实际意义值 >0 即可
返回值:成功时返回epoll文件描述符,失败时返回-1

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:控制epoll属性
    epfd:epoll_create函数的返回句柄。7、】=
    op:表示动作类型。有三个宏 来表示:
            EPOLL_CTL_ADD:注册新的fdepfd
            EPOLL_CTL_MOD:修改已注册fd的监听事件
            EPOLL_CTL_DEL:从epfd中删除一个fd
    Fd:需要监听的fd
            event:告诉内核需要监听什么事件
            EPOLLIN:表示对应文件描述符可读
            EPOLLOUT:可写
            EPOLLPRI:有紧急数据可读;
            EPOLLERR:错误;
            EPOLLHUP:被挂断;
            EPOLLET:触发方式,边缘触发;(默认使用边缘触发)
             ET模式:表示状态的变化;
返回值:成功时返回0,失败时返回-1

typedef union epoll_data 
{
      void* ptr;(无效)
      int fd;
      uint32_t u32;
      uint64_t u64;
epoll_data_t;
struct epoll_event 
{
    uint32_t events; / * Epoll事件* /
    epoll_data_t data; / *用户数据变量* /
};
//等待事件到来
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
功能:等待事件的产生,类似于select的用法
     epfd:句柄;
     events:用来保存从内核得到事件的集合;
     maxevents:表示每次能处理事件最大个数;
     timeout:超时时间,毫秒,0立即返回,-1阻塞
成功时返回发生事件的文件描述个数,失败时返回-1

select,poll都属于 同步IO机制(轮询)

epoll属于异步IO机制(不轮询): 

epoll的提出--》它所支持的文件描述符上限是系统可以最大打开的文件的数目;

                       eg:1GB机器上,这个上限10万个左右。

每个fd上面有callback(回调函数)函数,只有产生事件的fd才有主动调用callback,不需要轮询。

注意:

  Epoll处理高并发,百万级

  1. 红黑树: 是特殊的二叉树(每个节点带有属性),Epoll怎样能监听很多个呢?首先创建树的根节点,每个节点都是一个fd以结构体的形式存储(节点里面包含了一些属性,callback函数)
  2. 就绪链表: 当某一个文件描述符产生事件后,会自动调用callback函数,通过回调callback函数来找到链表对应的事件(读时间还是写事件)。

2、epoll特点

  1. 监听的最大的文件描述符没有个数限制(取决与你自己的系统 1GB - 10万个左右)
  2. 异步I/O,epoll当有事件产生被唤醒之后,文件描述符主动调用callback(回调函数)函数直接拿到唤醒的文件描述符,不需要轮询,效率高

3.epoll不需要重新构造文件描述符表,只需要从用户空间向内核空间拷贝一次数据即可.

3、epoll的流程: 

Epoll的使用:

1.创建红黑树 和 就绪链表         

2.添加文件描述符和事件信息到树上

3.阻塞等待事件的产生,一旦产生事件,则进行处理

4.根据链中准备处理的文件描述符 进行处理

epoll 要使用一组函数:  epoll_create 创建红黑树 和 就序列表

                                      epoll_ctl   添加文件描述符和事件到树上 / 从树上删除

                                     epoll_wait  等待事件产生

1)epoll_create 创建红黑树以及链表
头文件:#include <sys/epoll.h>
声明:int epoll_create(int size); 
功能:创建红黑树根节点(创建epoll实例) , 同时也会创建就绪链表
返回值:成功时返回一个实例(二叉树句柄),失败时返回-1
2)epoll_ctl 控制epoll属性

声明: int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

功能:控制epoll属性,比如给红黑树添加节点

参数: 1. epfd:   epoll_create函数的返回句柄。//一个标识符
     2. op:表示动作类型,有三个宏:			        
                EPOLL_CTL_ADD:注册新的fd到epfd中
			      EPOLL_CTL_MOD:修改已注册fd的监听事件
			      EPOLL_CTL_DEL:从epfd中删除一个fd
     3. 要操作的文件描述符
     4. 结构体信息: 
 typedef union epoll_data 
{
     int fd;      //要添加的文件描述符
     uint32_t u32;  typedef unsigned int
     uint64_t u64;   typedef unsigned long int
} epoll_data_t;

struct epoll_event 
{
   uint32_t events; 事件
   epoll_data_t data; //共用体(看上面)
};

	  关于events事件:
			 EPOLLIN:  表示对应文件描述符可读
		    EPOLLOUT: 可写
			 EPOLLPRI:有紧急数据可读;
		    EPOLLERR:错误;
		    EPOLLHUP:被挂断;
			 EPOLLET:触发方式,边缘触发;(默认使用边缘触发)
			 ET模式:表示状态的变化;
           NULL: 删除一个文件描述符使用,无事件
           
返回值:成功:0, 失败:-1


3)epoll_wait等待事件产生
声明: int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

功能:等待事件产生
   内核会查找红黑树中有事件响应的文件描述符, 并将结构体放入就绪链表
    就绪链表中的内容, 执行epoll_wait会同时复制到第二个参数events

参数: 	epfd:句柄;
		events:用来保存从就绪链表中响应事件的集合;
		maxevents:  表示每次在链表中拿取响应事件的个数;
		timeout:超时时间,毫秒,0立即返回  ,-1阻塞	

返回值: 成功: 实际从链表中拿出的数目     失败时返回-1


练习epoll实现服务器端

#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/epoll.h>
int main(int argc, char const *argv[])
{
    if (argc < 2)
    {
        printf("plase input <ip><port>\n");
        return -1;
    }
    //1.创建套接字,用于链接
    int sockfd;
    int acceptfd;
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        return -1;
    }
    printf("sockfd:%d\n", sockfd);
    //2.绑定 ip+port 填充结构体
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;                   //协议族ipv4
    saddr.sin_port = htons(atoi(argv[1]));        //端口号,htons将无符号短整数hostshort从主机字节顺序到网络字节顺序。
    saddr.sin_addr.s_addr = inet_addr("0.0.0.0"); //ip地址,转化为16进制表示
    socklen_t len = sizeof(saddr);                //结构体大小
    //bind绑定ip和端口
    if (bind(sockfd, (struct sockaddr *)&saddr, len) < 0)
    {
        perror("bind err");
        return -1;
    }
    printf("bind success\n");
    //3.启动监听,把主动套接子变为被动套接字
    if (listen(sockfd, 1) < 0)
    {
        perror("listen err");
        return -1;
    }
    printf("listen success\n");
   
    
    //引入epoll
    //创建结构体变量
    struct epoll_event event;
    struct epoll_event revents[32];//存放epoll_wait拿取的内容
    //1.创建树
    int epfd=epoll_create(1);
    // if (epfd = epoll_creat(1) < 0)
    // {
    //     perror(" creat err");
    //     return -1;
    // }
    //2.将关心的文件描述符添加到树上
    //标准输入上树
    event.events = EPOLLIN | EPOLLET;
    event.data.fd = 0;
    epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &event);
    //套接字上树
    event.data.fd = sockfd;
    epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event);

    char buf[64] = {0};//字符数组
    //3.在链表中取事件

    while (1)
    {
        //3.阻塞 等待文件描述符产生事件
        int ret = epoll_wait(epfd, revents, 10, -1);
        if (ret < 0)
        {
            perror(" epoll_wait err");
            return -1;
        }
        //4.根据文件描述符 进行处理
        for (int i = 0; i < ret; i++)
        {
            if (revents[i].data.fd == 0)
            {
                //5.执行操作
                fgets(buf, sizeof(buf), stdin);
                if (buf[strlen(buf)] == '\0') //去掉fgets补的'\n'
                {
                    buf[strlen(buf) - 1] = '\0';
                }
                    send(event.data.fd, buf, sizeof(buf), 0); //发送

            }
            else if (revents[i].data.fd == sockfd)
            {
                int acceptfd = accept(sockfd, (struct sockaddr *)&saddr, &len);
                if (acceptfd < 0)
                {
                    perror("accept is err:");
                    return -1;
                }
                printf("fd: %d ip: %s   port: %d is connect\n",acceptfd, inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));

                event.data.fd = acceptfd;//新的acceptfd上树
                event.events = EPOLLIN | EPOLLET;
                epoll_ctl(epfd, EPOLL_CTL_ADD, acceptfd, &event);
            }
            else
            {
                int recvbyte = recv(revents[i].data.fd, buf, sizeof(buf), 0);
                if (recvbyte < 0)
                {
                    perror("recv is err:");
                    return -1;
                }
                else if (recvbyte == 0)
                {
                    printf("client is exit\n");
                    close(revents[i].data.fd);
                    epoll_ctl(epfd, EPOLL_CTL_DEL, revents[i].data.fd, NULL);
                }
                else
                {
                    printf("%d : %s\n", revents[i].data.fd, buf);
                }
            }
        }
    }
    close(sockfd);
    close(acceptfd);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1191602.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国密算法SSL证书

国密算法&#xff0c;即国家商用密码算法&#xff0c;是中国政府推动的一项密码算法标准&#xff0c;目的是提高我国信息安全水平。这一标准覆盖了对称密码算法、非对称密码算法、哈希函数等多个方面。在SSL证书领域&#xff0c;国密算法的应用对于保障网络通信的安全至关重要。…

YB1205B S0T23开关式异步升压具恒压恒流LED驱动器

YB1205B S0T23开关式异步升压具恒压恒流LED驱动器 产品简介&#xff1a; YB1205B是一种输入电压范围宽(0.85.5V),可调恒定电流和限定电流两种模式来驱动白光LED而设计的升压型DCDC变换器。采用变频模式&#xff0c;逐周期限流&#xff0c;使输入输出电流随电源电压降低均匀变…

全局前置路由守卫(beforeEach)

全局前置路由守卫&#xff08;beforeEach&#xff09; 功能&#xff1a;每一次切换任意路由组件之前都会被调用&#xff0c;相当于在进入另一个路由组件之前设置一个权限。 路由守卫的存在意义就是在不同的时间&#xff0c;不同的位置&#xff0c;去添加代码。如&#xff1a;J…

招聘信息采集

首先&#xff0c;我们需要使用PHP的curl库来发送HTTP请求。以下是一个基本的示例&#xff1a; <?php // 初始化curl $ch curl_init();// 设置代理 curl_setopt($ch, CURLOPT_PROXY, "jshk.com.cn");// 设置URL curl_setopt($ch, CURLOPT_URL, "http://www…

echarts图从隐藏到显示以后大小有问题的解决方法

大家好&#xff0c;我是南宫。 今天分享一个刚刚解决的问题。 稍微介绍一下问题的背景&#xff1a; 我有一个绘制柱状图的需求&#xff0c;之前已经画好了&#xff0c;没想到今天对接数据的时候发现&#xff0c;如果没有数据&#xff0c;后端是直接返回一个空数组的。&#…

面向对象高级

本期对应知识库&#xff1a;&#xff08;持续更新中&#xff01;&#xff09; 面向对象高级 (yuque.com) ​​​​​​​尚硅谷_宋红康_对象内存解析.pptx static 适用于公用变量 开发中&#xff0c;变量 经常把一些常量设置为静态static 例如 PI 方法 经常把工具类中的方…

RapidSSL证书

RapidSSL是一家经验丰富的证书颁发机构&#xff0c;主要专注于提供标准和通配符SSL证书的域验证SSL证书。在2017年被DigicertCA收购后&#xff0c;RapidSSL改进了技术并开始使用现代基础设施。专注于为小型企业和网站提供基本安全解决方案的SSL加密。RapidSSL它具有强大的浏览器…

股票四倍杠杆什么意思?

股票四倍杠杆是指投资者通过借款或使用金融衍生品&#xff0c;以增加其投资股票的能力&#xff0c;达到放大投资回报的目的。具体来说&#xff0c;投资者可以通过向券商或银行等金融机构借入资金&#xff0c;或者使用融资融券等金融衍生品&#xff0c;以增加其购买股票的资本&a…

SAM + 用于文本到图像修复的稳定扩散

推荐基于稳定扩散(stable diffusion) AI 模型开发的自动纹理工具&#xff1a; DreamTexture.js自动纹理化开发包 - NSDT 什么是SAM&#xff1f; 今年早些时候&#xff0c;Meta AI 发布了新的开源项目&#xff1a;Segment Anything Model &#xff08;SAM&#xff09;&#xff…

智慧工地建筑施工项目管理平台源码,实现人员劳务实名制管理、区域安防监控、智能AI识别、用电/水监控、噪音扬尘监测、现场物料管理等功能

智慧工地管理系统源码&#xff0c;智慧工地云平台源码&#xff0c;PC端APP端源码 智慧工地管理平台实现对人员劳务实名制管理、施工进度、安全管理、设备管理、区域安防监控系统、智能AI识别系统、用电/水监控系统、噪音扬尘监测、现场物料管理系统等方面的实时监控和管理&…

使用U盘安装ubuntu22操作教程

U盘启动 将烧录好的U盘&#xff0c;插上待安装系统的电脑 服务器在开机之后长按【ESC键】进入BIOS选项中&#xff0c;选择对应的U盘启动 如下图&#xff0c;在界面中“USB”选项就是我的U盘&#xff0c;第一启动项选择U盘启动&#xff0c;其他启动项不动&#xff0c;选择后按F…

【计算思维题】少儿编程 蓝桥杯省赛考试计算思维真题 数学逻辑思维真题详细解析第11套

少儿编程 蓝桥杯青少组计算思维真题及解析 第十四届蓝桥杯省赛真题 1、晶晶在注册一个学习网站时,需要设置密码。网站提示: 密码必须由 8~16个字符组成,可以包合数字、大写字母、小写字母、特殊符号这 4种字符类型。 包含4种不同类型字符的密码是强密码; 包含2种或3种不…

软件开发项目文档系列之十五如何撰写项目结项报告

这是一个项目总结文档的说明文件&#xff0c;它提供了项目的概述、建设情况、技术情况、测试情况、培训情况、试运行情况、主要成效等详细信息。 1 项目概述 项目名称&#xff1a;明确指定了项目的名称&#xff0c;这有助于确保文件的清晰性和易读性。 项目相关单位&#xff…

「Java开发指南」如何用MyEclipse搭建Spring MVC应用程序?(二)

本教程将指导开发者如何生成一个可运行的Spring MVC客户应用程序&#xff0c;该应用程序实现域模型的CRUD应用程序模式。在本教程中&#xff0c;您将学习如何&#xff1a; 从数据库表的Scaffold到现有项目部署搭建的应用程序 使用Spring MVC搭建需要MyEclipse Spring或Bling授…

三相电机的某些实测特性曲线

三相电机参数&#xff1a; 0.75KW&#xff0c;额定电流是2A&#xff0c;功率因数0.71&#xff0c;效率78.9%。制式S1. 1.负载不变时的线电压与线电流的关系 1.1相关数据与python代码&#xff1a; 这里记录了一系列的实验&#xff1a; 第一组实验&#xff1a;近乎空载&#xf…

HTTParty库数据抓取代码示例

使用HTTParty库的网络爬虫程序&#xff0c; ruby require httparty # 设置服务器 proxy_host proxy_port # 使用HTTParty库发送HTTP请求获取网页内容 response HTTParty.get(/, :proxy > { :host > proxy_host, :port > proxy_port }) # 打印获取的网页内容 …

SpringBoot 配置进阶

一、ConfigurationProperties 1、 在类定义上 ConfigurationProperties注解&#xff0c;此注解是用来为bean绑定属性。使用步骤如下&#xff1a; 在配置文件 application.yml 中&#xff0c;添加配置信息 servers:ip-address: 127.0.0.1port: 8123创建配置类&#xff0c;并在…

ubuntu下Anaconda环境安装GPU的pytorch(docker镜像)

实验室需要给每个人分配docker的container环境&#xff0c;为了节省系统的空间&#xff0c;打算把anaconda和深度学习的开发环境配置好拉取镜像以省时间。 基础环境配置 apt更新了清华源 安装了基础环境 gcc vim Linux文本编辑库 openssh-server ssh远程连接库 net-tools 包含…

iEnglish马铁鹰:智能教育塑造未来学习新范式

随着云计算、大数据、物联网、人工智能和区块链等新一代智能技术在教育中的广泛应用&#xff0c;教育正日益迈向智能时代。智能化和智慧化将深刻改变未来教育形式和学习方式&#xff0c;为教育带来更多可能性和机遇。根据教育部统计数据&#xff0c;截至2022年底&#xff0c;中…

Spring Cloud 微服务入门篇

文章目录 什么是微服务架构 Microservice微服务的发展历史微服务的定义微小的服务微服务 微服务的发展历史1. 微服务架构的发展历史2. 微服务架构的先驱 微服务架构 Microservice 的优缺点1. 微服务 e Microservice 优点2. 微服务 Microservice 缺点微服务不是银弹&#xff1a;…