多路复用的学习

文章介绍了多路复用的概念,即使用一个进程监控多个文件描述符的读写操作,特别适用于并发量大但任务短小的场景,如Web服务器。文中详细讲解了select、pselect、poll和epoll四种多路复用技术的使用方法、优缺点以及它们在处理文件描述符集合和超时时间上的差异。epoll作为更高效的选择,具有条件触发和边缘触发两种模式,能减少事件触发次数,提高程序效率。
摘要由CSDN通过智能技术生成

多路复用:

    使用一个进程(且只有主线程),监控若干个文件描述符的读写操作,并作出对应的响应,这种读写模式称为多路复用

使用场景:

    多用于TCP的服务端,用于监控客户端的连接和收发数据

    适合并发量大,但任务量短小的情景,例如Web服务器

优点:

    不需要频繁地创建、销毁进程,从而节约了时间资源、内存资源,也避免了进程之间的资源竞争、等待

缺点:

    单个客户端的任务不能太耗时,其他客户端会感知到卡顿

select:

    fd_set  数据类型,是文件描述符的集合,使用以下函数进行操作

    void FD_SET(int fd, fd_set *set);

    功能:添加fd到集合set中

    void FD_CLR(int fd, fd_set *set);

    功能:从集合set中删除fd

    int  FD_ISSET(int fd, fd_set *set);

    功能:判断fd是否存在于集合set中

    返回值:存在返回非0,不存在返回0

    void FD_ZERO(fd_set *set);

    功能:清空集合set

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

    功能:监控多个文件描述符的读、写、异常等操作

    nfds:被监控的文件描述符中最大值+1

    readfds:监控读操作的文件描述符集合

    writefds:监控写操作的文件描述符集合

    exceptfds:监控异常操作的文件描述符集合

    timeout:设置超时时间

        NULL    一直阻塞,直到监控的某些文件描述符发生了对应变化

        0秒0微秒    非阻塞

        秒数>0   最多等待超时时间,超时后会返回0

    返回值:

        1、监控到发生了对应操作的文件描述符的数量

        2、超时返回0

        3、错误返回-1

    注意:

        readfds、writefds、exceptfds这三个集合参数既是输入也是输出,所以当调用select函数时需要往集合中存放被监控的文件描述符,当函数监控成功返回后会把发生了操作的文件描述符存入到集合中,需要读取

    select设计不合理地方:

        1、每次调用select时都需要重新向它传递被监控的集合

        2、调用结束后若想知道具体是哪些文件文件描述符发生了对应的操作,需要把所有监控的文件描述符都通过FD_ISSET测试一遍

    select优点:

        它是最早的多路复用函数,几乎所有的操作系统都支持,程序的兼容性很高

pselect:

    int pselect(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, const struct timespec *timeout,const sigset_t *sigmask);

    功能:功能与select大致相同,多一些增加的功能,相当于select的增强版,但是本质没有区别,缺点一致

    区别:

        1、超时时间的结构类型不同,pselect精度更高

        2、pselect还可以输出剩余时间

        3、pselect监听时可用通过sigmask设置要屏蔽的信号,可以保障pselect监控某些信号的干扰

    缺点一致

poll:

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

    功能:监控某些文件描述符

    fds:struct pollfd结构数组

    nfds:fds结构数组的长度

    timeout:设置超时时间

    返回值:

        1、监控到发生了对应操作的文件描述符的数量

        2、超时返回0

        3、错误返回-1

    //  一个pollfd对应一个被监控的文件描述符

    struct pollfd {

        int   fd;         //被监控的文件描述符

        short events;     //想要监控的事件

        short revents;    //实际监控到的事件

    };

    events/revents可选参数:

        POLLIN  普通优先级的读事件

        POLLOUT 普通优先级的写事件

        POLLPRI 高优先级的读事件

        POLLRDHUP   对方socket关闭事件

        POLLERR 通信错误事件,只能在revents中获取

        POLLHUP 对方挂起事件

        POLLNVAL   非法描述符,只能在revents中获取

epoll:

    int epoll_creat(int size);

    功能:创建rpoll对象,该对象可以用于保存被监控的文件描述符

    size:epoll对象监控文件描述符的数量

    返回值:返回一个epoll对象的描述符

   

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

    功能:控制epoll对象,如:添加、删除、修改监控文件描述符

    epfd:epoll对象描述符

    op:

        EPOLL_CTL_ADD   添加描述符

        EPOLL_CTL_MOD   修改描述符要监控的事件

        EPOLL_CTL_DEL   删除描述符

    fds:要操作的描述符

    event:要监控事件的结构体

    struct epoll_event {

        uint32_t     events;      //要监控的事件,参考poll的events 名字前加E

        epoll_data_t data;        //监控的fd赋给data.fd

    };

    返回值:成功返回0,失败返回-1

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

    功能:监控文件描述符,直接返回产生对应事件的文件描述符

    epfd:epoll对象描述符

    events:输出型参数,用于存储发生了事件的描述符数组

    maxevents:用于声明监控可以返回的最多描述符数量

    timeout:超时时间

    返回值:

        1、监控到发生了对应操作的文件描述符的数量

        2、超时返回0

        3、错误返回-1

    与select对比的优点:

        1、只需要准备一次要监控的描述符

        2、会把发生了事件的描述符返回,不需要想select一样遍历所有的描述符

        3、编程结构更简洁

epoll的条件触发和边缘触发:

    条件触发:当文件缓冲区中有需要读取的数据时,就会触发事件

        epoll默认的模式

        类似按键盘

    边缘触发:当数据产生发送动作时就会触发一次事件,如果缓冲区中还有需要读取的数据时不再触发事件

        1、被监控的描述符的事件增加EPOLLET 边缘触发

        2、要循环读取数据直到读取完毕

        3、recv读取必须以非阻塞MSG_DONTWAIT读取

        4、当recv的返回值为-1时读取完毕,0表示连接断开

        优点:某些情况下大大降低事件触发的次数,从而提高程序运行效率

        类似鼠标单击

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值