Linux 下 poll模型

来源:互联网 发布:大数据专业课程设置 编辑:程序博客网 时间:2024/06/05 08:19

poll调用和select调用实现的功能一样,都是网络IO利用的一种机制。poll() 没有像 select() 构建 fd_set 结构体的 3 个数组 ( 针对每个条件分别有一个数组 : 可读性、可写性和错误条件 ) ,然后检查从 0 到 nfds 每个文件描述符。


先看一下poll的调用形式


一,poll调用

[cpp] view plain copy
  1. #include <poll.h>  
  2. int poll(struct pollfd fds[], nfds_t nfds, int timeout);  


二,参数说明

fds:存放需要被检测状态的Socket描述符;与select不同(select函数在调用之后,会清空检测socket描述符的数组),每当调用这个函数之后,系统不会清空这个数组,而是将有状态变化的描述符结构的revents变量状态变化,操作起来比较方便;

nfds:用于标记数组fds中的struct pollfd结构元素的总数量;

timeout:poll函数调用阻塞的时间,单位是MS(毫秒)


struct pollfd结构如下:【在源码文件poll.h文件中】

[cpp] view plain copy
  1. struct pollfd {  
  2.     int fd;          /* poll 的文件描述符.  */
  3.     short events;    /* fd 上感兴趣的事件(等待的事件).*/
  4.     short revents;   /* fd 上实际发生的事件.  */
  5. };  

这个结构中

fd表示文件描述符,

events表示请求检测的事件位掩码

常量说明POLLIN普通或优先级带数据可读POLLRDNORM普通数据可读POLLRDBAND优先级带数据可读POLLPRI高优先级数据可读POLLOUT普通数据可写POLLWRNORM普通数据可写POLLWRBAND优先级带数据可写POLLERR发生错误POLLHUP发生挂起POLLNVAL描述字不是一个打开的文件

 注意:后三个只能作为描述字的返回结果存储在revents中,而不能作为测试条件用于events中。

revents表示检测之后返回的事件位掩码,如果当某个文件描述符有状态变化时,revents的值就不为空。 



三,返回值

  1. 大于0:表示数组fds中有socket描述符的状态发生变化,或可以读取、或可以写入、或出错。并且返回的值表示这些状态有变化的socket描述符的总数量;此时可以对fds数组进行遍历,以寻找那些revents不空的socket描述符,然后判断这个里面有哪些事件以读取数据。
  2. 等于0:表示没有socket描述符有状态变化,并且调用超时。
  3. 小于0:此时表示有错误发生,此时全局变量errno保存错误码。


服务端

#include <stdio.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>          /* See NOTES */#include <sys/socket.h>#include <netinet/in.h>#include <netinet/ip.h> /* superset of previous */#include <sys/time.h>#include <arpa/inet.h>#include <poll.h>#define backlog 5#define BUFFSIZE 1024int create_listenfd(const char *ip, unsigned short port){    int listenfd = socket(PF_INET, SOCK_STREAM, 0);    if(-1 == listenfd)    {        perror("socket");        return -1;    }        struct sockaddr_in serv_addr;    memset(&serv_addr, 0, sizeof(serv_addr));    serv_addr.sin_family = AF_INET;    serv_addr.sin_port = htons(port);    serv_addr.sin_addr.s_addr = (ip == NULL ? INADDR_ANY :inet_addr(ip));        if(-1 == bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)))    {        perror("bind");        close(listenfd);        return -1;    }    printf("bind success!\n");        if(-1 == listen(listenfd, backlog))    {        perror("listen");        close(listenfd);        return -1;    }    printf("listening ...\n");        return listenfd;}int main(int argc, char *argv[]){    int listenfd = create_listenfd(NULL,atoi(argv[2]));    if(-1 == listenfd)     {        return 0;    }        char buff[BUFFSIZE];    int recvbytes, sendbytes;    struct pollfd eventfds[BUFFSIZE];    memset(eventfds, 0, sizeof(eventfds));    eventfds[0].fd = STDIN_FILENO;    eventfds[0].events = POLLIN;    eventfds[1].fd = listenfd;    eventfds[1].events = POLLIN;        while(1)    {            int ret = poll(eventfds, BUFFSIZE, 3*1000);        if(-1 == ret)        {            perror("poll");            break;        }        else if(0 == ret)        {            printf("timeout...\n");        }        else        {            for(int i = 0; i <= BUFFSIZE; i++)            {                int fd = eventfds[i].fd;                if(eventfds[i].revents & POLLIN)                {                    if(fd == STDIN_FILENO)                    {                        fgets(buff, sizeof(buff), stdin);                        printf("gets:%s",buff);                    }                    else if(fd == listenfd)                    {                        int connectfd = accept(listenfd, NULL, NULL);                        if(-1 == connectfd)                        {                            perror("accept");                            close(listenfd);                            return 0;                        }                        printf("A new client(fd=%d) is connect success!\n", connectfd);                        eventfds[connectfd - listenfd + 1].fd = connectfd;                        eventfds[connectfd - listenfd + 1].events = POLLIN;                    }                    else                    {                        recvbytes = recv(fd, buff, sizeof(buff), 0);                        if(recvbytes < 0)                        {                            perror("recv");                            eventfds[i].events = 0;                            eventfds[i].fd = -1;                            close(fd);                            break;                        }                        if(recvbytes == 0)                        {                            printf("client(fd=%d) is closed!\n", fd);                            eventfds[i].events = 0;                            eventfds[i].fd = -1;                            close(fd);                            break;                        }                        printf("server recv from client(fd=%d):%s", fd, buff);                    }                                    }            }        }    }       close(listenfd);    return 0;}


客户端

#include <stdio.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>          /* See NOTES */#include <sys/socket.h>#include <netinet/in.h>#include <netinet/ip.h> /* superset of previous */#define backlog 5#define BUFFSIZE 1024int main(int argc, char *argv[]){    int sockfd = socket(PF_INET, SOCK_STREAM, 0);    if(-1 == sockfd)    {        perror("socket");        exit(EXIT_FAILURE);    }    struct sockaddr_in serv_addr;    memset(&serv_addr, 0, sizeof(serv_addr));    serv_addr.sin_family = AF_INET;    serv_addr.sin_port = htons(atoi(argv[2]));    serv_addr.sin_addr.s_addr = inet_addr(argv[1]);    if(-1 == connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)))    {        perror("connect");        close(sockfd);        exit(EXIT_FAILURE);    }    printf("connect success!\n");    char buff[BUFFSIZE];    int recvbytes, sendbytes;    while(1)    {        fgets(buff, sizeof(buff), stdin);        if(0 == strncmp(buff, "quit", 4))        {            printf("client quit!\n");            break;        }        sendbytes = send(sockfd, buff, strlen(buff)+1, 0);        if(sendbytes <= 0)        {            perror("send");            break;        }    }    close(sockfd);    return 0;}



运行

./server 127.0.0.1 8888
./client 127.0.0.1 8888
./client 127.0.0.1 8888

原创粉丝点击