码迷,mamicode.com
首页 > 其他好文 > 详细

epoll实现IO复用,TCP通信

时间:2016-05-26 22:15:57      阅读:257      评论:0      收藏:0      [点我收藏+]

标签:poll

函数原型:

技术分享

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

参数说明:

技术分享

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的设置参数:


技术分享

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

#include<stdio.h>                                                               
#include<stdlib.h>
#include<string.h>
#include<poll.h>
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‘;
                            printf("%s",buf);
                        }
                        fds[i].revents=0;
                    }
                //  else if(fds[i].fd==1&&fds[i].revents&&POLLOUT)
                //  {
                //      strcpy(buf,"hello");
                //      printf("echo: %s",buf);
                //      fds[i].revents=0;
                //  }
                }
            }
            break;
        }
    }
    return 0;
}

TCP通信:监听socket

server:

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

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

  3. accept新连接

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

  4. 检查现有连接

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

poll与select不同在于描述符存储方式不同。

结构体数组的管理:当每次有需要关心的描述符时,将其放入结构体中,每次有无效的描述符后,在下次调用前需要把其从结构体清除。

//server:优质版
#include<stdio.h>                                                       
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<poll.h>
#include<string.h>
#include<errno.h>
#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(i<j)
        {
            while(i<j&&polls[i].fd!=-1)//从前面数第一个无效的
                ++i;
            while(i<j&&polls[j].fd==-1)//从后面数第一个有效的
                --j;
            if(i<j)//复制fd
            {
                polls[i].fd=polls[j].fd;
                polls[i].events=POLLIN;//可不需要,因为event参数不发生变化,本程序只监听读事件
                polls[index].revents=0;
            }                             
        }
        index=i;
        //printf("%d",index);
        //须保证polls是有序的
        switch(poll(polls,index,timeout))//index表明最后一个关心的描述符在数组中下标+1=个数
        {
            case 0://timeout
                printf("time out...\n");
                break;
            case -1://error
                perror("poll");
                break;
            default://normal
            {
                for(i=0;i<index;++i)
                {
                    if(polls[i].fd==listen_sock&&(polls[i].revents&                        POLLIN))
                    {
                        printf("get a connect\n");
                        int new_sock=accept(listen_sock,                        (struct sockaddr*)&remote,&len);
                        if(new_sock<0)
                        {      
                            perror("accept");
                            continue;
                        }
                        if(index==_SIZE_)
                        {
                            printf("full");
                            close(new_sock);
                            return -1;
                        }
                        polls[index].fd=new_sock;
                        polls[index].events=POLLIN;
                        polls[index].revents=0;
                        ++index;
                    }
                    else if(polls[i].fd>0&&(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;i<index;++i)
                {
                    if(polls[i].fd==listen_sock&&(polls[i].revents&                        POLLIN))         
                    {
                        printf("get a connect\n");
                        int new_sock=accept(listen_sock,                        (struct sockaddr*)&remote,&len);
                        if(new_sock<0)
                        {
                            perror("accept");
                            continue;
                        }
                        int j;
                        for(j=0;j<_SIZE_;++j)
                        {
                            if(fds[j]==-1)
                            {
                                fds[j]=new_sock;
                                break;
                            }
                        }
                        if(j==_SIZE_)
                        {                         
                            printf("full");
                            close(new_sock);
                            return -1;
                        }
                        polls[i].revents=0;//reset
                    }
                    else if(polls[i].fd>0&&(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<stdio.h>                                                       
#include<stdlib.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
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;
}

运行截图:

技术分享

本文出自 “小止” 博客,请务必保留此出处http://10541556.blog.51cto.com/10531556/1783601

epoll实现IO复用,TCP通信

标签:poll

原文地址:http://10541556.blog.51cto.com/10531556/1783601

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!