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不提供支持),可移植性差;
代码示例(转载)
服务器
- #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 <stdlib.h>
- #include <errno.h>
- #include <stdio.h>
- #include <string.h>
- #include <poll.h> /* poll function */
- #include <limits.h>
- #define MAXLINE 10240
- #ifndef OPEN_MAX
- #define OPEN_MAX 40960
- #endif
- void handle(struct pollfd* clients, int maxClient, int readyClient);
- int main(int argc, char **argv)
- {
- int servPort = 6888;
- int listenq = 1024;
- int listenfd, connfd;
- struct pollfd clients[OPEN_MAX];
- int maxi;
- socklen_t socklen = sizeof(struct sockaddr_in);
- struct sockaddr_in cliaddr, servaddr;
- char buf[MAXLINE];
- int nready;
- bzero(&servaddr, socklen);
- servaddr.sin_family = AF_INET;
- servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- servaddr.sin_port = htons(servPort);
- listenfd = socket(AF_INET, SOCK_STREAM, 0);
- if (listenfd < 0) {
- perror("socket error");
- }
- int opt = 1;
- if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
- perror("setsockopt error");
- }
- if(bind(listenfd, (struct sockaddr *) &servaddr, socklen) == -1) {
- perror("bind error");
- exit(-1);
- }
- if (listen(listenfd, listenq) < 0) {
- perror("listen error");
- }
- clients[0].fd = listenfd;
- clients[0].events = POLLIN;
- int i;
- for (i = 1; i< OPEN_MAX; i++)
- clients[i].fd = -1;
- maxi = listenfd + 1;
- printf("pollechoserver startup, listen on port:%d\n", servPort);
- printf("max connection is %d\n", OPEN_MAX);
- for ( ; ; ) {
- nready = poll(clients, maxi + 1, -1);
- //printf("nready is %d\n", nready);
- if (nready == -1) {
- perror("poll error");
- }
- if (clients[0].revents & POLLIN) {
- connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &socklen);
- sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
- printf(buf, "");
- for (i = 0; i < OPEN_MAX; i++) {
- if (clients[i].fd == -1) {
- clients[i].fd = connfd;
- clients[i].events = POLLIN;
- break;
- }
- }
- if (i == OPEN_MAX) {
- fprintf(stderr, "too many connection, more than %d\n", OPEN_MAX);
- close(connfd);
- continue;
- }
- if (i > maxi)
- maxi = i;
- --nready;
- }
- handle(clients, maxi, nready);
- }
- }
- void handle(struct pollfd* clients, int maxClient, int nready) {
- int connfd;
- int i, nread;
- char buf[MAXLINE];
- if (nready == 0)
- return;
- for (i = 1; i< maxClient; i++) {
- connfd = clients[i].fd;
- if (connfd == -1)
- continue;
- if (clients[i].revents & (POLLIN | POLLERR)) {
- nread = read(connfd, buf, MAXLINE);//读取客户端socket流
- if (nread < 0) {
- perror("read error");
- close(connfd);
- clients[i].fd = -1;
- continue;
- }
- if (nread == 0) {
- printf("client close the connection");
- close(connfd);
- clients[i].fd = -1;
- continue;
- }
- write(connfd, buf, nread);//响应客户端
- if (--nready <= 0)//没有连接需要处理,退出循环
- break;
- }
- }
- }
客户端
- #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 1024
- void 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);
- }
- }
- linux 网络编程【四】 非阻塞通信poll
- linux 网络编程【四】 非阻塞通信poll
- linux 网络编程【四】 非阻塞通信poll
- Java网络编程四 非阻塞通信UDP
- Java网络编程四 非阻塞通信UDP
- linux 网络编程【三】 非阻塞通信select
- linux 网络编程【五】 非阻塞通信epoll
- linux 网络编程【三】 非阻塞通信select
- linux 网络编程【五】 非阻塞通信epoll
- linux 网络编程【五】 非阻塞通信epoll
- Python网络编程基础笔记-poll实现非阻塞socket
- 四. 非阻塞通信
- 四. 非阻塞通信
- 四. 非阻塞通信
- Linux网络编程--非阻塞编程
- UNIX环境高级编程学习之第十六章网络IPC:套接字 - 非阻塞的Socket通信Poll模型(多路复用), 实用Socket通信模板
- linux下非阻塞网络编程-select
- Linux 网络编程二:非阻塞select
- linux 网络编程【一】 socket地址
- Java 开发环境搭建
- linux 网络编程【二】 基本阻塞通信
- linux 网络编程【三】 非阻塞通信select
- hadoop dfs下文件的操作
- linux 网络编程【四】 非阻塞通信poll
- CSS架构
- system库函数调用
- linux 网络编程【五】 非阻塞通信epoll
- lambda的一些用法
- Chromium的连接管理
- UIWindow的一点儿思考
- 如何编程隐藏Revit 中的组Group?
- 最小堆