int poll(struct pollfd *fds, nfds_t nfds, int timeout);
fds:监听的文件描述符【数组】
struct pollfd {
int fd: 待监听的文件描述符
short events: 待监听的文件描述符对应的监听事件
取值:POLLIN、POLLOUT、POLLERR
short revnets: 传入时, 给0。如果满足对应事件的话, 返回 非0 --> POLLIN、POLLOUT、POLLERR
}
**nfds: 监听数组的,实际有效监听个数。**
优点:
自带数组结构。 可以将 监听事件集合 和 返回事件集合 分离。
拓展 监听上限。 超出 1024限制。
缺点:
不能跨平台。 Linux
无法直接定位满足监听事件的文件描述符, 编码难度较大。
2.#include <stdio.h>
3.#include <stdlib.h>
4.#include <string.h>
5.#include <netinet/in.h>
6.#include <arpa/inet.h>
7.#include <poll.h>
8.#include <errno.h>
9.#include "wrap.h"
10.
11.#define MAXLINE 80
12.#define SERV_PORT 6666
13.#define OPEN_MAX 1024
14.
15.int main(int argc, char *argv[])
16.{
17. int i, j, maxi, listenfd, connfd, sockfd;
18. int nready;
19. ssize_t n;
20. char buf[MAXLINE], str[INET_ADDRSTRLEN];
21. socklen_t clilen;
22. struct pollfd client[OPEN_MAX];
23. struct sockaddr_in cliaddr, servaddr;
24.
25. listenfd = Socket(AF_INET, SOCK_STREAM, 0);
26.
27. bzero(&servaddr, sizeof(servaddr));
28. servaddr.sin_family = AF_INET;
29. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
30. servaddr.sin_port = htons(SERV_PORT);
31.
32. Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
33.
34. Listen(listenfd, 20);
35.
36. client[0].fd = listenfd;
37. client[0].events = POLLRDNORM; /* listenfd监听普通读事件 */
38.
39. for (i = 1; i < OPEN_MAX; i++)
40. client[i].fd = -1; /* 用-1初始化client[]里剩下元素 */
41. maxi = 0; /* client[]数组有效元素中最大元素下标 */
42.
43. for ( ; ; ) {
44. nready = poll(client, maxi+1, -1); /* 阻塞 */
45. if (client[0].revents & POLLRDNORM) { /* 有客户端链接请求 */
46. clilen = sizeof(cliaddr);
47. connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
48. printf("received from %s at PORT %d\n", //打印客户端地址结构
49. inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
50. ntohs(cliaddr.sin_port));
51. for (i = 1; i < OPEN_MAX; i++) { /
52. if (client[i].fd < 0) {
53. client[i].fd = connfd; /* 找到client[]中空闲的位置,存放accept返回的connfd */
54. break;
55. }
56. }
57.
58. if (i == OPEN_MAX)
59. perr_exit("too many clients");
60.
61. client[i].events = POLLRDNORM; /* 设置刚刚返回的connfd,监控读事件 */
62. if (i > maxi)
63. maxi = i; /* 更新client[]中最大元素下标 */
64. if (--nready <= 0)
65. continue; /* 没有更多就绪事件时,继续回到poll阻塞 */
66. }
67. for (i = 1; i <= maxi; i++) { /* 检测client[] */
68. if ((sockfd = client[i].fd) < 0)
69. continue;
70. if (client[i].revents & (POLLRDNORM | POLLERR)) {
71. if ((n = Read(sockfd, buf, MAXLINE)) < 0) {
72. if (errno == ECONNRESET) { /* 当收到 RST标志时 */
73. /* connection reset by client */
74. printf("client[%d] aborted connection\n", i);
75. Close(sockfd);
76. client[i].fd = -1;
77. } else {
78. perr_exit("read error");
79. }
80. } else if (n == 0) {
81. /* connection closed by client */
82. printf("client[%d] closed connection\n", i);
83. Close(sockfd);
84. client[i].fd = -1;
85. } else {
86. for (j = 0; j < n; j++)
87. buf[j] = toupper(buf[j]);
88. Writen(sockfd, buf, n);
89. }
90. if (--nready <= 0)
91. break; /* no more readable descriptors */
92. }
93. }
94. }
95. return 0;
96.}