I/O多路转接之poll


这里写图片描述
poll函数与select原理类似,只是poll没有为每个状态(可读、可写、异常)构造一个描述符集,而是构造了一个pollfd结构体数组,每个数组元素指定一个描述符编号以及对其关心的状态。
这里写图片描述
参数2:nfds 是nfds_t类型的参数,用于标记结构体数组fds的数组元素的总数量;
参数3:timeout是poll函数阻塞的时间,单位:毫秒;
1、0:poll 函数立即返回而不阻塞;
2、INFTIM:即负数,那么poll函数会一直阻塞下去,直到所检测的描述符上所关心的事件发生;
3、timeout指定时间:poll()函数会以轮询方式在timeout所指定的毫秒时间之后返回;
返回值:
1、成功:返回数组fds中已就绪的读、写或出错状态的描述符的总数量;
2、timeout超时:返回0;
3、失败:-1;
poll函数的特点:每当调用这个函数之后,系统不会清空fds这个数组,操作起来比较方便;特别是对于socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select函数不同,调用select函数之后,select函数会清空它所检测的描述符集合,导致每次调用select之前都必须把描述符重新加入到待检测的集合中;因此,select函数适合于只检测一个描述符的情况,而poll函数适合于大量描述符的情况。虽然pollfd并没有最大数量限制,但是select和poll都需要在返回后,通过遍历文件描述符来获取已经就绪的文件描述符。事实上,同时连接的大量客户端在同一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。
使用poll实现一个tcp服务器

//server端:
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/poll.h>
#include<stdlib.h>
#define _SIZE 64
int array_rfds[1024];
static void Usage(const char* proc)
{
    printf("Usage:%s [local_ip][local_port]\n",proc);
}
int Startup(const char* _ip,int _port)
{
    int sock= socket(AF_INET,SOCK_STREAM,0);
    if(sock<0)
    {
        perror("socket");
        exit(1);
    }
    int flag = 1;
    setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));

    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port= htons(_port);
    server.sin_addr.s_addr = inet_addr(_ip);
    if(bind(sock,(struct sockaddr*)&server,sizeof(server))<0)
    {
        perror("bind");
        exit(2);
    }

    if(listen(sock,10)<0)
    {
        perror("listen");
        exit(3);
    }
    return sock;
}
int main(int argc,const char* argv[])
{
    if(argc!=3)
    {
        Usage(argv[0]);
        return 1;
    }
    int listen_sock = Startup(argv[1],atoi(argv[2]));
    struct pollfd _pollfd[_SIZE];
    _pollfd[0].fd = listen_sock;
    _pollfd[0].events = POLLIN;
    _pollfd[0].revents = 0;
    int timeout = 0;
    int i = 1;
    int max_num = 1;
    for(;i <_SIZE;i++)
    {
        _pollfd[i].fd = -1;
    }
    while(1)
    {
        timeout = 5000;

        switch(poll(_pollfd,max_num,timeout))
        {
            case 0:
                printf("timeout...\n");
                break;
            case -1:
                perror("poll");
                break;
            default:
                {
                    for(i = 0;i<max_num;++i)
                    {
                        if(_pollfd[i].fd == listen_sock &&\
                                _pollfd[i].revents & POLLIN)
                        {
                            struct sockaddr_in client;
                            socklen_t len = sizeof(client);
                            int new_sock = accept(listen_sock,\
                                    (struct sockaddr*)&client,&len);
                            if(new_sock<0)
                            {
                                perror("accept");
                                continue;
                            }
                            printf("new client--> %s:%d\n",\
                                    inet_ntoa(client.sin_addr),\
                                    ntohs(client.sin_port));
                            int j =1;
                            for(;j<64;++j)
                            {
                                if(_pollfd[j].fd == -1)
                                {
                                    _pollfd[j].fd = new_sock;
                                    _pollfd[j].events = POLLIN;
                                    _pollfd[j].revents = 0;
                                    break;
                                }
                            }
                            if(j == _SIZE)
                            {
                                close(new_sock);
                            }
                            if(j == max_num)
                                max_num++;
                        }
                        else if(_pollfd[i].fd != listen_sock && _pollfd[i].revents&POLLIN)
                        {
                            char buf[1024];
                            ssize_t s= read(_pollfd[i].fd,buf,sizeof(buf)-1);
                            if(s>0)
                            {
                                buf[s] = 0;
                                printf("client say: %s\n",buf);
                            }
                            else if(s ==0)
                            {
                                printf("client is quit!!\n");
                                close(_pollfd[i].fd);
                                _pollfd[i].fd = -1;
                            }
                            else
                            {
                                perror("read");
                                close(_pollfd[i].fd);
                                _pollfd[i].fd = -1;
                            }   
                        }
                    }
                }
                break;
        }
    }
    for(i=0;i<_SIZE;++i)
    {
        if(_pollfd[i].fd !=-1)
            close(_pollfd[i].fd);
    }
    return 0;
}
//client端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void usage(const char* proc)
{
    printf("Usage:%s[server_ip][server_port]\n",proc);
}
int main(int argc,char *argv[])
{
    if(argc != 3)
    {
        usage(argv[0]);
        return 1;
    }
    int sock = socket(AF_INET,SOCK_STREAM,0);
    if(sock<0)
    {
        perror("socket");
        return 2;
    }
    struct sockaddr_in peer;
    peer.sin_family = AF_INET;
    peer.sin_port = htons(atoi(argv[2]));
    peer.sin_addr.s_addr = inet_addr(argv[1]);
    int ret = connect(sock,(struct sockaddr*)&peer,sizeof(peer));
    if(ret<0)
    {
        perror("connect");
        printf("%s\n",strerror(ret));
        return 3;
    }
    char buf[1024];
    while(1)
    {
        printf("please enter: ");
        fflush(stdout);
        ssize_t s=read(0,&buf,sizeof(buf));
        if(s<0)
        {
            perror("read");
            return 4;
        }
        buf[s-1]=0;
        write(sock,&buf,strlen(buf));
        printf("server echo: %s\n",buf);        
    }
    close(sock);
    return 0;
}

这里写图片描述
这里写图片描述

poll模型的优点:
1、相对于select模型来说,高效。每当调用poll函数之后,系统不会清空fds这个数组,操作起来比较方便;特别是对于文件描述符连接比较多的情况下,在一定程度上可以提高处理的效率。
2、处理了select模型监视文件句柄有上限的问题;
poll模型的缺点:虽然pollfd并没有最大数量限制,但是select和poll都需要在返回后,通过遍历文件描述符来获取已经就绪的文件描述符。事实上,同时连接的大量客户端在同一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值