网络编程、poll轮询、select机制

本文详细比较了select和poll两种I/O多路复用机制,包括它们的函数接口、实现原理、优点和效率分析。select通过fd_set集合管理,poll则使用structpollfd数组,后者在减少集合数上提供空间优势但遍历效率可能下降。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

具体实现机制:
    1. select机制
        1) 函数接口:
        /* According to POSIX.1-2001 */
        #include <sys/select.h>
                
        /* According to earlier standards */
        #include <sys/time.h>
        #include <sys/types.h>
        #include <unistd.h>
                
        int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
        参数:
            参数1:nfds表示的是集合中最大文件描述符+1;
            参数2:readfds表示关心的读事件集合,不关心用NULL填充
            参数3:writefds表示关心的写事件集合,不关心用NULL填充
            参数4:exceptfds表示关心的其它事件集合,不关心用NULL填充
            参数5:timeout用来设置阻塞事件
                  a, 设置为NULL,表示检测时一直阻塞,直到有事件准备就绪函数才返回
                  b, 设置结构体的值
                      struct timeval {
                        long    tv_sec;         /* seconds */
                        long    tv_usec;        /* microseconds */
                    };
                    1) 成员的值都0,非阻塞方式检测;
                    2) 成员值为非零,有阻塞时间。
        返回值:
            成功返回值准备就绪事件的个数;
            返回0表示检测超时
            失败返回-1,且修改errno的值。
                            
        void FD_CLR(int fd, fd_set *set);    /* 将文件描述符fd从集合set中移除 */
        int  FD_ISSET(int fd, fd_set *set);    /* 检测文件描述符fd是否在集合set,如果在返回非0,不在返回0 */
        void FD_SET(int fd, fd_set *set);    /* 将文件描述符fd添加到集合set中 */
        void FD_ZERO(fd_set *set);            /* 清空集合set */
                            
        2) 具体实现的思路:
            a,创建读事件集合readfds,并清空集合
                fd_set readfds;
                FD_ZERO(&readfds);
                                    
            b,将文件描述符listenfd添加到读事件集合readfds中;
                FD_SET(listenfd, &readfds);
                                    
            c,检测集合中是否有准备就绪的事件(阻塞方式检测,有事件准备就绪函数返回)
                ret = select(nfds, &readfds, NULL, NULL, NULL);
                                
            d,得到准备就绪事件的文件描述符
                for(fd = 0; fd < nfds; fd++) {
                    if (FD_ISSET(fd, &readfds)) {
                        e,对fd进IO操作。
                    }
                }
        3) 特征:
            a,可以在一个任务中对多个阻塞io进程操作,谁先准备就绪,就操作谁。
            b,如果操作事件不同,需要定义多个集合;
            c,找到准备就绪的文件描述符的时候,需要从0遍历到最大的文件描述符。效率很低。    

   2. poll机制       

相关函数接口:
            #include <poll.h>
            int poll(struct pollfd *fds, nfds_t nfds, int timeout);
            参数:
                参数1:fds表示是IO操作的集合(数组)首元素的地址
                    struct pollfd {
                        int   fd;         /* file descriptor */
                        short events;     /* requested events */
                        short revents;    /* returned events */
                    };
                    events / revents:
                    POLLIN    :读事件;
                    POLLOUT    :写事件;        
             参数2:nfds表示表示fds中的有效项数;
             参数3:timeout表示事件检测时间(是以ms为单位)
                        如果timeout = -1,表示以阻塞的方式去检测,没有事件准备就绪就一直阻塞,直到有事件准备就绪才返回。
                        如果timeout > 0 阻塞时间为timeout
                        如果timeout = 0 非阻塞方式;

            2) poll机制的具体是实现流程:
                a,创建集合,并清空集合
                    struct pollfd fds[1024];
                    memset(fds, 0, sizeof(fds));
                    for (i = 0; i < 1024; i++)
                        fds[i].fd = -1;
                b,将文件描述符listenfd及其对应的读写事件(POLLIN、POLLOUT)添加到集合fds中;
                    fds[0].fd = listenfd;
                    fds[0].events = POLLIN | POLLOUT;
                    nfds = 1;
                while(1) {
                    c,调用poll函数,检测是否有准备就绪的事件,如果没有事件准备就绪,函数一直阻塞。如果有事件准备就绪函数返回;
                    ret = poll(fds, nfds, -1);

                    d, 找到准备就绪事件的文件描述符;
                        for(i = 0; i < nfds; i++) {
                            if (fds[i].fd == -1) 
                                continue;
                            fd = fds[i].fd;
                            if (fds[i].revents == POLLIN) {
                                e,处理读事件,IO读操作
                            } else if (fds[i].revents == POLLOUT) {
                                e,处理写事件,IO写操作
                            }
                        }
                }

                优缺点: 
                    1. 集合数减少,空间增大;
                    2. 效率提高;依然会对集合中所有元素进行遍历。(随着集合中元素的增多效率会下降)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

clown_30

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值