读书人

linux 网络编程【4】 非阻塞通信poll

发布时间: 2013-02-24 17:58:56 作者: rapoo

linux 网络编程【四】 非阻塞通信poll
函数原型

#include <poll.h>
int poll(struct pollfd fds[], nfds_t nfds, int timeout);

typedef struct pollfd {
int fd; /* 需要被检测或选择的文件描述符*/
short events; /* 对文件描述符fd上感兴趣的事件 */
short revents; /* 文件描述符fd上当前实际发生的事件*/
} pollfd_t;


typedef unsigned long nfds_t;

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

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

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

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

==0:数组fds中没有任何socket描述符准备好读、写,或出错;此时poll超时,超时时间是timeout毫秒;换句话说,如果所检测的socket描述符上没有任何事件发生的话,那么poll()函数会阻塞timeout所指定的毫秒时间长度之后返回,如果timeout==0,那么poll() 函数立即返回而不阻塞,如果timeout==INFTIM,那么poll() 函数会一直阻塞下去,直到所检测的socket描述符上的感兴趣的事件发生是才返回,如果感兴趣的事件永远不发生,那么poll()就会永远阻塞下去;

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

特殊说明

如果待检测的socket描述符为负值,则对这个描述符的检测就会被忽略,也就是不会对成员变量events进行检测,在events上注册的事件也会被忽略,poll()函数返回的时候,会把成员变量revents设置为0,表示没有事件发生;


另外,poll() 函数不会受到socket描述符上的O_NDELAY标记和O_NONBLOCK标记的影响和制约,也就是说,不管socket是阻塞的还是非阻塞的,poll()函数都不会收到影响;而select()函数则不同,select()函数会受到O_NDELAY标记和O_NONBLOCK标记的影响,如果socket是阻塞的socket,则调用select()跟不调用select()时的效果是一样的,socket仍然是阻塞式TCP通讯,相反,如果socket是非阻塞的socket,那么调用select()时就可以实现非阻塞式TCP通讯;


所以poll() 函数的功能和返回值的含义与 select() 函数的功能和返回值的含义是完全一样的,两者之间的差别就是内部实现方式不一样,select()函数基本上可以在所有支持文件描述符操作的系统平台上运行(如:Linux 、Unix 、Windows、MacOS等),可移植性好,而poll()函数则只有个别的的操作系统提供支持(如:SunOS、Solaris、AIX、HP提供支持,但是Linux不提供支持),可移植性差;

代码示例(转载)服务器

#include  <unistd.h>#include  <sys/types.h>       /* basic system data types */#include  <sys/socket.h>      /* basic socket definitions */#include  <netinet/in.h>      /* sockaddr_in{} and other Internet defns */#include  <arpa/inet.h>       /* inet(3) functions */#include <netdb.h> /*gethostbyname function */#include <stdlib.h>#include <errno.h>#include <stdio.h>#include <string.h>#define MAXLINE 1024void handle(int connfd);int main(int argc, char **argv){    char * servInetAddr = "127.0.0.1";    int servPort = 6888;    char buf[MAXLINE];    int connfd;    struct sockaddr_in servaddr;    if (argc == 2) {        servInetAddr = argv[1];    }    if (argc == 3) {        servInetAddr = argv[1];        servPort = atoi(argv[2]);    }    if (argc > 3) {        printf("usage: echoclient <IPaddress> <Port>\n");        return -1;    }    connfd = socket(AF_INET, SOCK_STREAM, 0);    bzero(&servaddr, sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_port = htons(servPort);    inet_pton(AF_INET, servInetAddr, &servaddr.sin_addr);    if (connect(connfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {        perror("connect error");        return -1;    }    printf("welcome to echoclient\n");    handle(connfd);     /* do it all */    close(connfd);    printf("exit\n");    exit(0);}void handle(int sockfd){    char sendline[MAXLINE], recvline[MAXLINE];    int n;    for (;;) {        if (fgets(sendline, MAXLINE, stdin) == NULL) {            break;//read eof        }        /*        //也可以不用标准库的缓冲流,直接使用系统函数无缓存操作        if (read(STDIN_FILENO, sendline, MAXLINE) == 0) {            break;//read eof        }        */        n = write(sockfd, sendline, strlen(sendline));        n = read(sockfd, recvline, MAXLINE);        if (n == 0) {            printf("echoclient: server terminated prematurely\n");            break;        }        write(STDOUT_FILENO, recvline, n);        //如果用标准库的缓存流输出有时会出现问题        //fputs(recvline, stdout);    }}


读书人网 >编程

热点推荐