Linux下I/O模式---IO多路复用(poll)2

承接上次select后面
函数poll也能实现io多路复用

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
   参p数:
   struct pollfd *fds
     关心的文件描述符数组struct pollfd fds[N];
   nfds:个数
   timeout: 超时检测
    毫秒级的:如果填10001秒
     如果-1,阻塞

 struct pollfd {
     int   fd;         /* 检测的文件描述符 */
     short events;     /* 检测事件 */
     short revents;    /* 调用poll函数返回填充的事件,poll函数一旦返回,将对应事件自动填充结构体这个成员。只需要判断这个成员的值就可以确定是否产生事件 */
 };
    事件: POLLIN :读事件
                POLLOUT : 写事件
               POLLERR:异常事件

实例(简易服务器):

//io并发准备工作
    struct pollfd fds[20] = {};

    fds[0].fd = 0; //把关注的描述符放进表里
    fds[0].events = POLLIN; //设置描述符的事件
    fds[1].fd = sockfd;
    fds[1].events = POLLIN;

    int nfds = 2;//表中变量数量

    char buf[128];
    int ret, i, recvbyte, nfdstemp;

    //4.阻塞等待客户端链接,链接成功返回一个通信文件描述符
    while (1)
    {

        ret = poll(fds, nfds, 2000);
        if (ret < 0)
        {
            perror("select err");
            return -1;
        }
        else if (ret == 0)
        {
            printf("timeout ----- \n");
        }
        else 
        {
            // nfdstemp = nfds; //临时用来便利的,防止后面改maxfd出错(我不知道有没有出错的可能)
            for (i = 0; i < nfds; i++)
            {
                if (fds[i].revents == POLLIN) //只有标志变量变了才能进来
                {
                    if (fds[i].fd == 0)
                    {
                        fgets(buf, sizeof(buf), stdin);
                        printf("stdin: %s\n", buf);
                    }
                    else if (fds[i].fd == sockfd)
                    {
                        acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len); //接收咱们关心的描述符
                        if (acceptfd < 0)
                        {
                            perror("accept err");
                            return -1;
                        }
                        fds[nfds].fd = acceptfd; //继续把关心的描述符放进表里,等它动弹时关心它
                        fds[nfds].events = POLLIN;
                        nfds++;

                        printf("用户 %d 已登录:ip:%s ,port:%d\n",
                               acceptfd, inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port)); //全服通告
                    }
                    else
                    {
                        recvbyte = recv(fds[i].fd, buf, sizeof(buf), 0); //
                        if (recvbyte < 0)
                        {
                            perror("recv err");
                            return -1;
                        }
                        else if (recvbyte == 0) //退出很麻烦,要多费心
                        {
                            printf("用户%d 已退出\n", fds[i].fd);
                            close(fds[i].fd);       //再关闭描述符
                            fds[i] = fds[nfds - 1]; //先把它从表里踢出去
                            i--;
                            nfds--;
                        }
                        else
                        {
                            printf("用户%d: %s \n", fds[i].fd, buf); //它给的东西
                        }
                    }
                }
            }
        }
        
    }

poll的特点:

  1. 优化文件描述符个数的限制;(根据poll函数第一个函数的参数来定,如果监听的事件为1个,则结构体数组元素个数为1,如果想监听100个,那么这个结构体数组的元素个数就为100,由程序员自己来决定)
  2. poll被唤醒之后需要重新轮询一遍驱动的poll函数,效率比较低
  3. poll不需要重新构造文件描述符表,只需要从用户空间向内核空间拷贝一次数据即可
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值