poll 使用的结构体如下
struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ short revents; /* returned events */};
需要使用该结构体数组对文件描述符进行注册,poll 通过该数组返回结果。事件就绪时需要遍历所有注册的文件描述符。
源码
#include#include #include #include #include #include #include #include #include #define SERV_PORT 9000#define LISTENQ 10#define OPEN_MAX 1024#define MAXLINE 1024int main(int argc, char **argv){ int listenfd, connfd, sockfd; int nready, maxi, i, n; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; struct pollfd client[OPEN_MAX]; char buf[MAXLINE]; /* 创建 socket */ if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(EXIT_FAILURE); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); /* 绑定地址到 socket */ if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { perror("bind"); exit(EXIT_FAILURE); } /* 转为监听 socket */ if (listen(listenfd, LISTENQ)) { perror("listen"); exit(EXIT_FAILURE); } client[0].fd = listenfd; client[0].events = POLLRDNORM; for (i = 1; i < OPEN_MAX; ++i) { client[i].fd = -1; } maxi = 0; for ( ; ; ) { nready = poll(client, maxi + 1, 1000); if (nready < 0) { perror("poll"); exit(EXIT_FAILURE); } else if (nready == 0) { fprintf(stderr, "timeout\n"); } if (client[0].revents & POLLRDNORM) { /* 监听 socket 上读事件 */ clilen = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen); if (connfd == -1) { perror("accept"); continue; } fprintf(stderr, "accept %d\n", connfd); /* 从client 数组中找到一个空位 */ for (i = 1; i < OPEN_MAX; i++) { if (client[i].fd < 0) { client[i].fd = connfd; break; } } if (i == OPEN_MAX) { fprintf(stderr, "too many clients"); exit(EXIT_FAILURE); } client[i].events = POLLRDNORM; if (i > maxi) { maxi = i; } if (--nready <= 0) { continue; } } /* 剩余的文件描述符 */ for (i = 1; i <= maxi; ++i) { if ((sockfd = client[i].fd) < 0) continue; if (client[i].revents & (POLLRDNORM | POLLERR)) { /* 读事件 */ if ((n = read(sockfd, buf, MAXLINE)) < 0) { if (errno == ECONNRESET) { close(sockfd); client[i].fd = -1; } else { fprintf(stderr, "read error"); } } else if (n == 0) { /* 客户端关闭连接 */ close(sockfd); client[i].fd = -1; } else { /* 回写数据到客户端 */ write(sockfd, buf, n); } if (--nready <= 0) { break; } } } } return 0;}
参考资料
《UNP》