poll事件机制

serv.c

  1. 基本知识

    poll的机制与select类似,与select在本质上没有多大差别;同样是轮询多个描述符,再根据描述符的状态进行处理;但是poll没有描述符数量的限制,这个与机器的上限有关;缺点与select类似即需要将大量的描述符从用户态复制至内核态;而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增加。

  2. 函数

    int poll(struct pollfd * pollfds,int timeout)
    struct pollfd{
    int fd ; //文件描述符
    short events ; // 等待发生的 事件
    short revents ;// 实际发生的事件
    }
    使用poll与select不一样,因为它们在合适的时候总是会从revents返回;POLLIN | POLLPRI 等价于select的读事件;POLLOUT|POLLWRBAND 等价于select的写事件;而POLLOUT等价于POLLWRNORM。注意这些表示并不是互斥的,它们可以被同时设置,表示这个文件描述符的读取和写入都会正常返回而不阻塞。timeout参数指定等待的毫秒数,无论I/O是否准备好,poll都会返回。timeout指定为负数表示无限超时,使poll一直挂起直到一个指定事件的发生。

    事件 events

    • POLLIN 有数据可读
    • POLLRDNORM 有普通数据可读
    • POLLRDBAND 有优先数据可读
    • POLLPRI 有紧急数据可读
    • POLLOUT 数据可写
    • POLLWRNORM 普通数据可写
    • POLLWRBAND 优先数据可写
    • POLLMSGSIGPOLL 消息可用

      返回事件 revent

      除了 事件外;还有
    • POLLERR 指定描述符发生错误
    • POLLHUP 指定文件描述符挂起事件
    • POLLNVAL 指定描述符非法
  3. 服务端代码

#include
#include
#include
#include

#include
#include
#include
#include
#include
#include


#define IPADDRESS "127.0.0.1"
#define PORT      9090
#define LISTENNUM 5
#define MAXOPEN   1000

/*
    @funcation name : socketBind 
    @description: create socket and bind the address
    @return
        succ : listenfd 
        fail : -1 
*/
int socketBind(char *ip,int port)
{
    int listenfd ;
    struct sockaddr_in servAddr ;

    listenfd  = socket(AF_INET,SOCK_STREAM,0) ;
    if (listenfd < 0)
    {
        printf("listenfd create is error:%d\n",errno) ;
        return -1 ;
    }

    bzero(&servAddr,sizeof(struct sockaddr_in)) ;

    servAddr.sin_family= AF_INET ;
    servAddr.sin_addr.s_addr = inet_addr(ip) ;
    //inet_pton(AF_INET,ip,&servAddr.sin_addr) ;
    servAddr.sin_port = htons(port) ;


    int ret = bind(listenfd,(struct sockaddr*)&servAddr,sizeof(servAddr)) ;
    if (ret < 0)
    {
        printf("bind is error:%d\n",errno) ;
        return -1 ;
    }

    return listenfd ;

}
/*
    @funcation name : handleConnection 
    @description: handle the client socket 
    @return
        succ : 0 
        fail : -1 
*/
int handleConnection(struct pollfd *connfds,int num)
{
    int i , n ;
    char buf[1024] ;
    memset(buf,0,1024);
    printf("deal the conn num:%d\n",num) ;
    for(i = 1 ;i<=num;i++)
    {
        if(connfds[i].fd < 0)
            continue ;

        if(connfds[i].revents & POLLIN)
        {
AGAIN:
            n = read(connfds[i].fd,buf,1024) ;
            if(n <0)
            {
                if (errno == EINTR)
                {
                    goto AGAIN;
                }
                else
                {
                    close(connfds[i].fd) ;
                    printf("close a conn index:%d,err:%d\n",i,errno) ;
                    connfds[i].fd = -1 ;
                    return -1;
                }
            }
            else if(n==0)
            {
                printf("the socket is closed by the peer\n");
                close(connfds[i].fd) ;
                connfds[i].fd = -1 ;
            }
            else
            {
                buf[n] = '\0' ;
                printf("recv data is :%s\n",buf) ;
                write(connfds[i].fd,buf,n) ;
            }
        }
    }
    return 0 ;
}

/*
    @funcation name : doPoll 
    @description: deal the poll of sockets;
           this is main loop;
    @return
        succ : 0 
        fail : exit(-1)  ;
*/
int doPoll(int listenfd)
{
    int nReady = 0 ;
    int maxI = 0 ;
    int connfd =-1 ;
    int i = 0;
    struct sockaddr_in cliAddr ;
    socklen_t cliAddrLen ;

    struct pollfd clientfds[MAXOPEN] ;

    cliAddrLen = sizeof(struct sockaddr) ;

    memset(&cliAddr,0,sizeof(struct sockaddr_in)) ;

    clientfds[0].fd = listenfd ;
    clientfds[0].events = POLLIN  ;
    clientfds[0].revents = 0 ;

    for (i = 1 ;i1 ;
    }

    for(;;)
    {
        printf("poll start...\n") ;
        nReady = poll(clientfds,maxI+1,-1) ;
        if(nReady ==-1)
        {
            if(errno == EINTR)
                continue ;
            else
                exit(-1) ;
        }


        if(clientfds[0].revents & POLLIN)
        {
            printf("accept the connectin\n") ;

            connfd = accept(listenfd,(struct sockaddr*)&cliAddr,&cliAddrLen) ;
            printf("connfd:%d\n",connfd) ;
            if (connfd < 0)
            {
                printf("error:%d\n",errno) ;
                if (errno == EINTR)
                {
                    continue ;
                }
                else
                {
                    printf("some error:%d\n",errno) ;
                    exit(-1) ;
                }
            }
            printf("accept a new client:%s,%d\n",inet_ntoa(cliAddr.sin_addr),ntohs(cliAddr.sin_port)) ;

            for(i= 1 ;iif(clientfds[i].fd < 0)
                {
                    clientfds[i].fd = connfd ;
                    break ;
                }
            }

            if (i == MAXOPEN)
            {
                printf("too many clients.\n") ;
                exit(-1) ;
            }

            clientfds[i].events = POLLIN ;
            clientfds[i].revents = 0 ;

            maxI = (i > maxI) ? i:maxI;

            if(--nReady <= 0 )
                continue ;
        }
        else
        {
            printf("deal a conn\n") ;
            handleConnection(clientfds,maxI) ;
        }

    }

    return 0 ;
}

/*
    @funcation name : main 
    @description: 
    @return
        succ :  0
        fail : exit-1 )
*/
int main()
{
    int listenfd ;

    printf("init is ok\n") ;

    listenfd = socketBind(IPADDRESS,PORT) ;
    if (listenfd == -1)
    {
        return -1 ;
    }

    printf("create socket and bind is ok\n") ;
    int ret = listen(listenfd,LISTENNUM) ;
    if (ret < 0)
    {
        printf("listen is error\n") ;
        exit(-1) ;
    }
    printf("deal the poll\n") ;
    doPoll(listenfd) ;

    printf("error\n") ;
    close(listenfd) ;
    return 0 ;
}

4 客户端代码

#include
#include
#include
#include

#include
#include
#include
#include

#define IP "127.0.0.1"
#define PORT 9090
#define MAXLINE 1024

int main()
{
    struct sockaddr_in servAddr ;
    socklen_t servAddrLen ;
    int servfd = -1 ;
    char buf[MAXLINE] = "Mr.luo" ;
AGAIN:
    bzero(&servAddr,sizeof(struct sockaddr_in)) ;
    servAddrLen = sizeof(struct sockaddr) ;

    servAddr.sin_family = AF_INET ;
    inet_pton(AF_INET,IP,&servAddr.sin_addr);
    //servAddr.sin_addr.s_addr = inet_addr(IP) ;
    servAddr.sin_port = htons(PORT) ;

    servfd = socket(AF_INET,SOCK_STREAM,0) ;

    int ret = connect(servfd,(struct sockaddr*)&servAddr,servAddrLen) ;
    if (ret < 0)
    {
        if (errno == EINTR)
        {
            close(servfd) ;
            goto  AGAIN;
        }
        else
        {
            printf("error connect to serv:%d\n",errno) ;
            close(servfd) ;
            exit(-1) ;
        }
    }
    sleep(1);
    write(servfd,buf,strlen(buf)+1) ;
    memset(buf,0,MAXLINE);

    read(servfd,buf,MAXLINE) ;
    printf("read data is :%s\n",buf) ;
    close(servfd);
    return 0 ;
}

你可能感兴趣的:(C,TCP/IP)