首页 > 其他分享 >I/O 复用

I/O 复用

时间:2023-02-21 22:56:47浏览次数:27  
标签:epoll int 复用 描述符 fd include SIZE

select

介绍

#include <sys/select.h>
#include <sys/time.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);

void FD_CLR(int fd, fd_set *set);
int  FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);

功能:将多个文件描述符集中到一起监视

参数:

  • nfds:监视对象文件描述符的数量,传入最大的文件描述符值 +1
  • readfds:被监视“是否存在待读取数据”的文件描述符集合
  • writefds:被监视“是否可传输无阻塞数据”的文件描述符集合
  • exceptfds:被监视“是否发生异常”的文件描述符集合
  • timeout:超时信息

返回值:

  • 发生错误返回 -1,此时 timeout 的值是不确定的,设置 errno 为 EINTR
  • 超时返回 0
  • 正常返回发生事件的文件描述符数,向其传递的 fd_set 变量将发生变化,除被监视事件发生的文件描述符外,剩下所有位被置 0

简单使用

设置文件描述符,指定监视范围,设置超时,调用 select 函数,查看调用结果

// 程序功能:监视标准输入
#include <stdio.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>

#define BUF_SIZE 1024

char buf[BUF_SIZE];

int main()
{
    fd_set reads;
    FD_ZERO(&reads);
    FD_SET(0, &reads);
   
    while (1) {
        struct timeval timeout;
        timeout.tv_sec = 5;
        timeout.tv_usec = 0;
        
        int result;
        fd_set tmp = reads;
        result = select(1, &tmp, NULL, NULL, &timeout);
        if (result == -1) {
            puts("select() error!");
            break;
        } else if (result == 0) {
            puts("Time out!");
        } else {
            if (FD_ISSET(0, &tmp)) {
                int len = read(0, buf, BUF_SIZE);
                buf[len] = '\0';
                printf("message from console: %s", buf);
            }
	}
    }
    
    return 0;
}

注意事项

  • 调用 select 函数后,timeval 类型变量的时间将被替换为超时前剩余时间,因此每次调用 select 前都要重新设置
  • 将准备好的 fd_set 变量复制到 tmp 中传入,因为除发生变化的文件描述符对应位外,剩下的都被置 0,为了保存初值,必需复制

poll

介绍

#include <poll.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

功能:和 select 类似,在指定时间内轮询一定数量的文件描述符,测试其中是否有就绪者

参数:

  • fds:pollfd 数组,指定所有感兴趣的文件描述符上发生的可读、可写和异常等事件

    struct pollfd {
        int   fd;         /* file descriptor */
        short events;     /* requested events */
        short revents;    /* returned events */
    };
    

    常见事件类型:

    POLLIN

    POLLERR

  • nfds:被监听事件集合 fds 的大小

  • timeout:以 ms 为单位的等待事件,传递 -1 会一直等待直到事件发生

返回值:

  • 发生错误返回 -1
  • 超时返回 0
  • 正常返回发生事件的文件描述符数

简单使用

// 程序功能:监视标准输入
#include <stdio.h>
#include <unistd.h>
#include <poll.h>

#define BUF_SIZE 1024
#define POLL_SIZE 30

char buf[BUF_SIZE];

struct pollfd fds[POLL_SIZE];

int main()
{
    fds[0].fd = 0;
    fds[0].events |= POLLIN;
    
    while (1) {
        int result;
        result = poll(fds, POLL_SIZE, -1);
        if (result == -1) {
            puts("poll() error!");
            break;
        } else if (result == 0) {
            puts("Time out!");
        } else {
            if (fds[0].recents & POLLIN) {
                int len = read(0, buf, BUF_SIZE);
                buf[len] = '\0';
                printf("message from console: %s", buf);
            }
	}
    }
    
    return 0;
}

注意事项

epoll

介绍

#include <sys/epoll.h>

int epoll_create(int size);

功能:创建保存 epoll 文件描述符的空间

参数:

  • size:epoll 实例的大小

返回值:

  • 成功时返回 epoll 文件描述符
  • 失败时返回 -1
#include <sys/epoll.h>

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

功能:向空间注册或注销文件描述符

参数:

  • epfd:epoll 例程的文件描述符

  • op:指定对监视对象的操作

    • EPOLL_CTL_ADD
    • EPOLL_CTL_DEL
    • EPOLL_CTL_MOD
  • fd:监视对象文件描述符

  • event:

    typedef union epoll_data {
                   void        *ptr;
                   int          fd;
                   uint32_t     u32;
                   uint64_t     u64;
               } epoll_data_t;
    
    struct epoll_event {
    	uint32_t     events;      /* Epoll events */
        epoll_data_t data;        /* User data variable */
    };
    

    常见事件类型:

    EPOLLIN:需要读取数据的情况

    EPOLLET:以边缘触发的方式得到事件通知

返回值:

  • 成功返回 0
  • 失败返回 -1
#include <sys/epoll.h>

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

功能:等待文件描述符发生变化

参数:

  • epfd:epoll 例程的文件描述符
  • events:保存发生事件的结构体数组地址
  • maxevents:可保存的最大事件数
  • timeout:以 ms 为单位的等待事件,传递 -1 会一直等待直到事件发生

返回值:

  • 成功时返回发生事件的文件描述符数
  • 失败返回 -1

简单使用

// 程序功能:监视标准输入
  2 #include <stdio.h>
  3 #include <unistd.h>
  4 #include <sys/epoll.h>
  5 
  6 #define BUF_SIZE 1024
  7 #define EPOLL_SIZE 50
  8 
  9 char buf[BUF_SIZE];
 10 struct epoll_event ep_events[EPOLL_SIZE];
 11 
 12 int main()
 13 {
 14     int epfd = epoll_create(EPOLL_SIZE);
 15 
 16     struct epoll_event event;
 17     event.events = EPOLLIN;
 18     event.data.fd = 0;
 19     epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &event);
 20 
 21     while (1) {
 22         int event_cnt = epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);
 23         if (event_cnt == -1) {
 24             puts("epoll_wait() error!");
 25             break;
             }
 27 
 28         for (int i = 0; i < event_cnt; i++) {
 29             if (ep_events[i].data.fd == 0) {
 30                 int len = read(0, buf, BUF_SIZE);
 31                 buf[len] = '\0';
 32                 printf("message from console: %s", buf);
 33             }
 34         }
 35     }
 36 
 37     close(epfd);
 38 
 39     return 0;
 40 }

注意事项

  • epoll_create() 返回的文件描述符主要用于区分 epoll 例程。需要终止时,也要调用 close 函数

水平触发与边缘触发

水平触发:只要输入缓冲有数据就会一直通知该事件,epoll 默认以水平触发模式工作

边缘触发:输入缓冲收到数据时仅注册一次该事件。即使输入缓冲中还有数据也不会再进行注册

实现边缘触发:

  • 通过 error 变量验证错误原因
  • 为了完成非阻塞 IO,更改套接字特性

标签:epoll,int,复用,描述符,fd,include,SIZE
From: https://www.cnblogs.com/cong0221/p/17142822.html

相关文章

  • 面试官:你是怎样进行react组件代码复用的
    mixinMixin设计模式Mixin(混入)是一种通过扩展收集功能的方式,它本质上是将一个对象的属性拷贝到另一个对象上面去,可以拷贝多个属性到一个对象上,为了解决代码复用问题。常......
  • 通信小白基础学习---MIMO技术入门,含码字,层映射,天线端口,预编码,PMI,rank,TM模式,波束赋形,空
    以下内容来源于B站up主“捻叶成剑”,如有侵权,请联系本人删除!载波聚合技术是增加带宽(拓宽车道),2*2MIMO是增加天线(增加车道为双车道)还有空分多址(实际应用不多)接收两......
  • 高复用性自动化脚本设计实践
    作者:京东物流刘红妍导读:在自动化测试实践中,为了更好的契合被测业务场景,需要不断优化框架分层结构。本文结合产品模块化思路,意在介绍通过策略模式改造原本复杂分支语句代码,......
  • 高复用性自动化脚本设计实践
    作者:京东物流刘红妍导读:在自动化测试实践中,为了更好的契合被测业务场景,需要不断优化框架分层结构。本文结合产品模块化思路,意在介绍通过策略模式改造原本复杂分支语句代......
  • 传输层的多路复用与分解 & Socket究竟是啥
    每天净背八股了,计网,操作系统这些知识早都忘光了,昨天被CVTE的面试官问住了,当时回答的比较乱,并且有些地方答错了。特此重新学习总结。但是不得不说,CVTE的技术面试官好温柔好......
  • pageTools 一个复用的通知条
    <template><el-cardclass="page-tools"><el-rowtype="flex"align="middle"justify="space-between"><div><el-buttonv-if="text"......
  • Web开发的那点事--软件复用
    复用的战场1.前台CSS,JavaScript/jquery/AJAXHTML/JSP2.后台增删改查几乎一样。复用的级别代码:一行代码或几行代码函数:一个函数类:工具类组件:一个小的功能模块,比如......
  • 必知必会的设计原则——合成复用原则
     设计原则系列文章 必知必会的设计原则——单一职责原则必知必会的设计原则——开放封闭原则必知必会的设计原则——依赖倒置原则必知必会的设计原则——里氏替换原......
  • 好客租房67-render-props模式-3演示mouseover的组件的复用
    //导入reactimportReactfrom'react'importReactDOMfrom'react-dom'//导入组件//约定1:类组件必须以大写字母开头//约定2:类组件应该......
  • Redis网络模型,IO多路复用
    IO多路复用无论是阻塞l0还是非阻塞lO,用户应用在一阶段都需要调用recvfrom来获取数据,差别在于无数据时的处理方案:*如果调用recvfrom时,恰好没有数据,阻塞IO会使进程阻塞,非......