poll实现IO复用,TCP通信-创新互联

函数原型:

创新互联是专业的奉贤网站建设公司,奉贤接单;提供成都做网站、成都网站建设,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行奉贤网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!

poll实现IO复用,TCP通信

函数说明:该函数允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或经历一段指定的时间后才唤醒它。

参数说明:

poll实现IO复用,TCP通信

fds:是一个struct pollfd结构类型的数组,用于存放需要检测其状态的Socket描述符;

每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况;

nfds:nfds_t类型的参数,用于标记数组fds中的结构体元素的总数量;

timeout:是poll函数阻塞的时间,单位:毫秒;

  1. 如果timeout==0,那么poll() 函数立即返回而不阻塞

  2. 如果timeout==INFTIM,即负数,那么poll() 函数会一直阻塞下去,直到所检测的socket描述符上的感兴趣的事件发生是才返回,如果感兴趣的事件永远不发生,那么poll()就会永远阻塞下去;

  3. poll()函数会以轮询方式在timeout所指定的毫秒时间长度之后返回

返回值:

>0:数组fds中准备好读、写或出错状态的那些socket描述符的总数量;

==0:数组fds中没有任何socket描述符准备好读、写,或出错;此时poll超时,超时时间是timeout毫秒

-1: poll函数调用失败,同时会自动设置全局变量errno;

struct pollfd中event的设置参数:

poll实现IO复用,TCP通信

实现IO复用:关心输入输出条件就绪

#include                                                               
#include
#include
#include
int main()
{
    struct pollfd fds[2];
    fds[0].fd=0;
    fds[0].events=POLLIN;
    fds[0].revents=0;

    fds[1].fd=1;
    fds[1].events=POLLOUT;
    fds[1].revents=0;
    char buf[1024];
    ssize_t _s;
    int i=0;
    int timeout=5000;
    while(1)
    {
        timeout=5000;
        switch(poll(fds,2,timeout))
        {
            case -1://error
                perror("poll");
                break;
            case 0://timeout
                printf("time out\n");
                break;
            default:
            {
                for(i=0;i<2;++i)
                {
                    if(fds[i].fd==0&&fds[i].revents&POLLIN)
                    {
                        _s=read(0,buf,sizeof(buf)-1);
                        if(_s>0)
                        {
                            buf[_s]='\0';
                            if(strncmp(buf,"quit",4)==0)
                            {
                                close(fds[i].fd);
                                exit(0);
                            }
                            printf("echo:%s",buf);
                        } 
                        //fds[i].revents=0;//not need
                    }
                //  else if(fds[i].fd==1&&fds[i].revents&&POLLOUT)
                //  {
                //      strcpy(buf,"hello");
                //      printf("echo: %s",buf);
                //      fds[i].revents=0;//not need
                //  }
                }
            }
            break;
        }
    }
    return 0;
}

运行截图:

poll实现IO复用,TCP通信

TCP通信:监听socket

server:

  1. 创建监听套接字并初始化:调用socket,bind,listen,唯一描述符是监听描述符初始化数据结构。

  2. 阻塞于select:select等待某个事件发生或新客户连接的建立或是数据,FIN或RST的到达。

  3. accept新连接

    如果监听套接字变为可读,那么已建立一个新的连接,我们调用accept并更新相应数据结构。使用fds数组中第一个未用项记录这个已连接描述符。

  4. 检查现有连接

对于每个现有客户连接,我们要测试其描述符是否在select返回描述符集中,如果是就从该客户读取一行文本,并回显,输出。如果该客户关闭了连接,那么read将返回0,更新数据结构。

poll与select不同在于描述符存储方式不同和参数类型不同。

1.结构体数组的管理:当每次有需要关心的描述符时,将其放入结构体中,每次有无效的描述符后,将其描述符置-1,下次poll函数会忽略它。当有新的描述符加入时,从头遍历结构体,将为-1的元素设为要关心的描述符事件状态。切记:当新的描述符加到结构体数组末尾时要更新关心描述符个数,即poll第二个参数。

2.每次调用poll后,结构体元素revents会存储就绪事件状态,当每次重新调用poll之前时,系统会自己设置其为0,重新监听关心事件(不需要用户重新置0)

3.poll中参数不是输入,输出型,因此timeout,struct pollfd *fds参数不需重置,nfds看情况(参照第一点),而select函数是输入输出类型,每次调用前需重置。

//server:最终版
include                                                                        
#include
#include
#include
#include
#include
#include
#include
#include
#define _BACKLOG_ 5
#define _SIZE_ 64
static void usage(const char* proc)
{
    printf("%s [ip][port]\n",proc);
}
static int start(char* ip,int port)
{
    //1.create a socket
    int sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock<0)
    {
        perror("socket");
        exit(1);
    }
    //2.bind
    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_port=htons(port);
    local.sin_addr.s_addr=inet_addr(ip);
    if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
    {
        perror("bind");
        exit(2);
    }
    //3.set listen  state
    if(listen(sock,_BACKLOG_)<0)
    {
        perror("listen");
        exit(3);
    }
    return sock;
}
int main(int argc,char* argv[])
{
    if(argc!=3)
    {       
        usage(argv[0]);
        return 1;
    }
    int _port=atoi(argv[2]);
    char* _ip=argv[1];
    //listen_sock_fd
    int listen_sock=start(_ip,_port);
    struct  pollfd  polls[_SIZE_];//struct pollfd arrays
    int index=0;//effective fdnum
    int timeout=5000;//millseconds
    int i=0;//index
    polls[0].fd=listen_sock;
    polls[0].events=POLLIN;
    polls[0].revents=0;
    int max_num=1;
    for(i=1;i<_SIZE_;++i)
    {
        polls[i].fd=-1;
    }
    char buf[1024];
    ssize_t _s=0;
    struct sockaddr_in remote;//accept
    socklen_t len=sizeof(remote);                              
    while(1)
    {
        //new start
        //timeout=5000;
        switch(poll(polls,max_num,timeout))
        {
            case 0://timeout
                printf("time out...\n");
                break;
            case -1://error
                perror("poll");
                break;
            default://normal
            {
                for(i=0;i0&&(polls[i].revents&\
                        POLLIN))//read ready
                    {
                        _s=read(polls[i].fd,buf,sizeof(buf)-1);
                        if(_s>0)
                        {
                            buf[_s]='\0';
                            printf("client: %s",buf);
                            write(polls[i].fd,buf,strlen(buf));         
                            polls[i].revents=0;//not need
                        }
                        else if(_s==0)//client close
                        {
                            close(polls[i].fd);
                            polls[i].fd=-1;
                            printf("client is close\n");
                        }
                    }
                    else
                    {}
                }
            } 
            break;
        }
    }
    for(i=0;i<_SIZE_;++i)
    {
        if(polls[i].fd!=-1)
            close(polls[i].fd);
    }
    return 0;
}                                                                          
                                                              
//server:优质版
#include                                                       
#include
#include
#include
#include
#include
#include
#include
#include
#define _BACKLOG_ 5
#define _SIZE_ 64
static void usage(const char* proc)
{
    printf("%s [ip][port]\n",proc);
}
static int start(char* ip,int port)
{
    //1.create a socket
    int sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock<0)
    {
        perror("socket");
        exit(1);
    }
    //2.bind
    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_port=htons(port);
    local.sin_addr.s_addr=inet_addr(ip);
    if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
    {
        perror("bind");
        exit(2);
    }
    //3.set listen  state
    if(listen(sock,_BACKLOG_)<0)
    {
        perror("listen");
        exit(3);           
    }
    return sock;
}
int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        usage(argv[0]);
        return 1;
    }
    int _port=atoi(argv[2]);
    char* _ip=argv[1];
    //listen_sock_fd
    int listen_sock=start(_ip,_port);
    struct  pollfd  polls[_SIZE_];//struct pollfd arrays
    int index=0;//effective fdnum
    int timeout=5000;//millseconds
    int i=0;//index
    polls[0].fd=listen_sock;
    polls[0].events=POLLIN;
    polls[0].revents=0;
    ++index;
    for(i=1;i<_SIZE_;++i)
    {
        polls[i].fd=-1;    
    }
    char buf[1024];
    ssize_t _s=0;
    struct sockaddr_in remote;//accept
    socklen_t len=sizeof(remote);
    while(1)
    {
        //new start
        timeout=5000;
        int j=index;
        i=0;
        //消除struct pollfd中已不关心的描述符:前移,得到有效的最后一个元素下标
        while(i0&&(polls[i].revents&\
                        POLLIN))//read ready
                    {
                        _s=read(polls[i].fd,buf,sizeof(buf)-1);
                        if(_s>0)
                        {
                            buf[_s]='\0';
                            printf("client: %s",buf);
                            write(polls[i].fd,buf,strlen(buf));   
                            polls[i].revents=0;
                        }
                        else if(_s==0)//client close
                        {
                            close(polls[i].fd);
                            polls[i].fd=-1;
                            printf("client is close\n");
                        }
                    }
                    else
                    {}
                }
            }
            break;
        }
    }
    for(i=0;i<_SIZE_;++i)
    {
        if(polls[i].fd!=-1)
            close(polls[i].fd);
    }
    return 0;
} 
//仿select版,用辅助数组存储,没有利用poll结构体的优点,event不清空,开销大                                                              
int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        usage(argv[0]);
        return 1;
    }
    int _port=atoi(argv[2]);
    char* _ip=argv[1];
    //listen_sock_fd
    int listen_sock=start(_ip,_port);
    struct  pollfd  polls[_SIZE_];//struct pollfd arrays
    int index=0;//effective fdnum
    int timeout=5000;//millseconds
    int i=0;//index
    int fds[_SIZE_];
    fds[0]=listen_sock;  
    for(i=1;i<_SIZE_;++i)
    {
        fds[i]=-1;
    }
    char buf[1024];
    ssize_t _s=0;
    struct sockaddr_in remote;//accept
    socklen_t len=sizeof(remote);
    while(1)
    {
        index=0;//new start
        timeout=5000;
        for(i=0;i<_SIZE_;++i)
        {
            polls[i].fd=-1;
        }
        for(i=0;i<_SIZE_;++i)
        {
            if(fds[i]!=-1)
            {                  
                polls[index].fd=fds[i];
                polls[index].events=POLLIN;
                polls[index].revents=0;
                ++index;
            }
        }
        switch(poll(polls,index,timeout))
        {
            case 0://timeout
                printf("time out...\n");
                break;
            case -1://error
                perror("poll");
                break;
            default://normal
            {
                for(i=0;i0&&(polls[i].revents&\
                        POLLIN))//read ready
                    {
                        _s=read(polls[i].fd,buf,sizeof(buf)-1);
                        if(_s>0)
                        {
                            buf[_s]='\0';
                            printf("client: %s",buf);
                            write(polls[i].fd,buf,strlen(buf));
                        }
                        else if(_s==0)//client close
                        {
                            close(polls[i].fd);
                            int j;                     
                            for(j=0;j<_SIZE_;++j)
                            {
                                if(fds[j]==polls[i].fd)
                                {
                                    fds[j]=-1;
                                    break;
                                }
                            }
                            printf("client is close\n");
                        }
                    }
                    else
                    {}
                }
            }
            break;
        }
    }
    for(i=0;i<_SIZE_;++i)
    {                           
            if(fds[i]!=-1)
            close(fds[i]);
    }
    return 0;
}          
//client:
#include                                                       
#include
#include
#include
#include
#include
#include
#include
void Usage(const char* proc)
{
    printf("%s [ip][port]",proc);
}
int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        Usage(argv[0]);
        return 1;
    }
    int client_sock=socket(AF_INET,SOCK_STREAM,0);
    if(client_sock<0)
    {
        perror("socket");
        return 1;
    }
    struct sockaddr_in client;
    client.sin_family=AF_INET;
    client.sin_port=htons(atoi(argv[2]));
    client.sin_addr.s_addr=inet_addr(argv[1]);
    char buf[1024];
    ssize_t _s;
    if(connect(client_sock,(struct sockaddr*)&client,sizeof(client))<0)
    {
        perror("connection");
        return 2;
    }
    while(1)
    {
        printf("please enter:\n");
        _s=read(0,buf,sizeof(buf)-1);        
        if(_s>0)
            buf[_s]='\0';
        if(strncmp(buf,"quit",4)==0)
        {
            printf("client is quit\n");
            break;
        }
        write(client_sock,buf,_s);
        _s=read(client_sock,buf,sizeof(buf)-1);
        if(_s>0)
        {
            buf[_s]='\0';
            printf("server->client: %s",buf);
        }
    }
    close(client_sock);

    return 0;
}

运行截图:

poll实现IO复用,TCP通信

创新互联www.cdcxhl.cn,专业提供香港、美国云服务器,动态BGP最优骨干路由自动选择,持续稳定高效的网络助力业务部署。公司持有工信部办法的idc、isp许可证, 机房独有T级流量清洗系统配攻击溯源,准确进行流量调度,确保服务器高可用性。佳节活动现已开启,新人活动云服务器买多久送多久。


标题名称:poll实现IO复用,TCP通信-创新互联
分享路径:http://ybzwz.com/article/doohec.html