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

来源:互联网 发布:青岛飞拉利和淘宝比 编辑:程序博客网 时间:2024/05/16 17:15

函数原型

#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不提供支持),可移植性差;

代码示例(转载)

服务器

[cpp] view plaincopy
  1. #include  <unistd.h>  
  2. #include  <sys/types.h>       /* basic system data types */  
  3. #include  <sys/socket.h>      /* basic socket definitions */  
  4. #include  <netinet/in.h>      /* sockaddr_in{} and other Internet defns */  
  5. #include  <arpa/inet.h>       /* inet(3) functions */  
  6.   
  7. #include <stdlib.h>  
  8. #include <errno.h>  
  9. #include <stdio.h>  
  10. #include <string.h>  
  11.   
  12.   
  13. #include <poll.h> /* poll function */  
  14. #include <limits.h>  
  15.   
  16. #define MAXLINE 10240  
  17.   
  18. #ifndef OPEN_MAX  
  19. #define OPEN_MAX 40960  
  20. #endif  
  21.   
  22. void handle(struct pollfd* clients, int maxClient, int readyClient);  
  23.   
  24. int  main(int argc, char **argv)  
  25. {  
  26.     int servPort = 6888;  
  27.     int listenq = 1024;  
  28.     int listenfd, connfd;  
  29.     struct pollfd clients[OPEN_MAX];  
  30.     int  maxi;  
  31.     socklen_t socklen = sizeof(struct sockaddr_in);  
  32.     struct sockaddr_in cliaddr, servaddr;  
  33.     char buf[MAXLINE];  
  34.     int nready;  
  35.   
  36.     bzero(&servaddr, socklen);  
  37.     servaddr.sin_family = AF_INET;  
  38.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  39.     servaddr.sin_port = htons(servPort);  
  40.   
  41.     listenfd = socket(AF_INET, SOCK_STREAM, 0);  
  42.     if (listenfd < 0) {  
  43.         perror("socket error");  
  44.     }  
  45.   
  46.     int opt = 1;  
  47.     if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {  
  48.         perror("setsockopt error");  
  49.     }  
  50.   
  51.     if(bind(listenfd, (struct sockaddr *) &servaddr, socklen) == -1) {  
  52.         perror("bind error");  
  53.         exit(-1);  
  54.     }  
  55.     if (listen(listenfd, listenq) < 0) {  
  56.         perror("listen error");      
  57.     }  
  58.   
  59.     clients[0].fd = listenfd;  
  60.     clients[0].events = POLLIN;  
  61.     int i;  
  62.     for (i = 1; i< OPEN_MAX; i++)   
  63.         clients[i].fd = -1;   
  64.     maxi = listenfd + 1;  
  65.   
  66.     printf("pollechoserver startup, listen on port:%d\n", servPort);  
  67.     printf("max connection is %d\n", OPEN_MAX);  
  68.   
  69.     for ( ; ; )  {  
  70.         nready = poll(clients, maxi + 1, -1);  
  71.         //printf("nready is %d\n", nready);  
  72.         if (nready == -1) {  
  73.             perror("poll error");  
  74.         }  
  75.         if (clients[0].revents & POLLIN) {  
  76.             connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &socklen);  
  77.             sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);  
  78.             printf(buf, "");  
  79.   
  80.             for (i = 0; i < OPEN_MAX; i++) {  
  81.                 if (clients[i].fd == -1) {  
  82.                     clients[i].fd = connfd;  
  83.                     clients[i].events = POLLIN;  
  84.                     break;  
  85.                 }  
  86.             }  
  87.   
  88.             if (i == OPEN_MAX) {  
  89.                 fprintf(stderr, "too many connection, more than %d\n", OPEN_MAX);  
  90.                 close(connfd);  
  91.                 continue;  
  92.             }  
  93.   
  94.             if (i > maxi)  
  95.                 maxi = i;  
  96.   
  97.             --nready;  
  98.         }  
  99.   
  100.         handle(clients, maxi, nready);  
  101.     }  
  102. }  
  103.   
  104. void handle(struct pollfd* clients, int maxClient, int nready) {  
  105.     int connfd;  
  106.     int i, nread;  
  107.     char buf[MAXLINE];  
  108.   
  109.     if (nready == 0)  
  110.         return;  
  111.   
  112.     for (i = 1; i< maxClient; i++) {  
  113.         connfd = clients[i].fd;  
  114.         if (connfd == -1)   
  115.             continue;  
  116.         if (clients[i].revents & (POLLIN | POLLERR)) {  
  117.             nread = read(connfd, buf, MAXLINE);//读取客户端socket流  
  118.             if (nread < 0) {  
  119.                 perror("read error");  
  120.                 close(connfd);  
  121.                 clients[i].fd = -1;  
  122.                 continue;  
  123.             }  
  124.             if (nread == 0) {  
  125.                 printf("client close the connection");  
  126.                 close(connfd);  
  127.                 clients[i].fd = -1;  
  128.                 continue;  
  129.             }  
  130.   
  131.             write(connfd, buf, nread);//响应客户端    
  132.             if (--nready <= 0)//没有连接需要处理,退出循环  
  133.                 break;  
  134.         }  
  135.     }  
  136. }  


客户端

[cpp] view plaincopy
  1. #include  <unistd.h>  
  2. #include  <sys/types.h>       /* basic system data types */  
  3. #include  <sys/socket.h>      /* basic socket definitions */  
  4. #include  <netinet/in.h>      /* sockaddr_in{} and other Internet defns */  
  5. #include  <arpa/inet.h>       /* inet(3) functions */  
  6. #include <netdb.h> /*gethostbyname function */  
  7.   
  8. #include <stdlib.h>  
  9. #include <errno.h>  
  10. #include <stdio.h>  
  11. #include <string.h>  
  12.   
  13. #define MAXLINE 1024  
  14.   
  15. void handle(int connfd);  
  16.   
  17. int main(int argc, char **argv)  
  18. {  
  19.     char * servInetAddr = "127.0.0.1";  
  20.     int servPort = 6888;  
  21.     char buf[MAXLINE];  
  22.     int connfd;  
  23.     struct sockaddr_in servaddr;  
  24.   
  25.     if (argc == 2) {  
  26.         servInetAddr = argv[1];  
  27.     }  
  28.     if (argc == 3) {  
  29.         servInetAddr = argv[1];  
  30.         servPort = atoi(argv[2]);  
  31.     }  
  32.     if (argc > 3) {  
  33.         printf("usage: echoclient <IPaddress> <Port>\n");  
  34.         return -1;  
  35.     }  
  36.   
  37.     connfd = socket(AF_INET, SOCK_STREAM, 0);  
  38.   
  39.     bzero(&servaddr, sizeof(servaddr));  
  40.     servaddr.sin_family = AF_INET;  
  41.     servaddr.sin_port = htons(servPort);  
  42.     inet_pton(AF_INET, servInetAddr, &servaddr.sin_addr);  
  43.   
  44.     if (connect(connfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {  
  45.         perror("connect error");  
  46.         return -1;  
  47.     }  
  48.     printf("welcome to echoclient\n");  
  49.     handle(connfd);     /* do it all */  
  50.     close(connfd);  
  51.     printf("exit\n");  
  52.     exit(0);  
  53. }  
  54.   
  55. void handle(int sockfd)  
  56. {  
  57.     char sendline[MAXLINE], recvline[MAXLINE];  
  58.     int n;  
  59.     for (;;) {  
  60.         if (fgets(sendline, MAXLINE, stdin) == NULL) {  
  61.             break;//read eof  
  62.         }  
  63.         /* 
  64.         //也可以不用标准库的缓冲流,直接使用系统函数无缓存操作 
  65.         if (read(STDIN_FILENO, sendline, MAXLINE) == 0) { 
  66.             break;//read eof 
  67.         } 
  68.         */  
  69.   
  70.         n = write(sockfd, sendline, strlen(sendline));  
  71.         n = read(sockfd, recvline, MAXLINE);  
  72.         if (n == 0) {  
  73.             printf("echoclient: server terminated prematurely\n");  
  74.             break;  
  75.         }  
  76.         write(STDOUT_FILENO, recvline, n);  
  77.         //如果用标准库的缓存流输出有时会出现问题  
  78.         //fputs(recvline, stdout);  
  79.     }  

0 0
原创粉丝点击