poll服務器方法采用將監聽端口用數組存放起來,這樣就不需要輪詢的監聽整個文件描述符了
#include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout);struct pollfd {int fd; /* 文件描述符 */short events; /* 監控的事件 */short revents; /* 監控事件中滿足條件返回的事件 */};POLLIN 普通或帶外優先數據可讀,即POLLRDNORM | POLLRDBANDPOLLRDNORM 數據可讀POLLRDBAND 優先級帶數據可讀POLLPRI 高優先級可讀數據POLLOUT 普通或帶外數據可寫POLLWRNORM 數據可寫POLLWRBAND 優先級帶數據可寫POLLERR 發生錯誤POLLHUP 發生掛起POLLNVAL 描述字不是一個打開的文件nfds 監控數組中有多少文件描述符需要被監控timeout 毫秒級等待-1:阻塞等,#define INFTIM -1 Linux中沒有定義此宏0:立即返回,不阻塞進程>0:等待指定毫秒數,如當前系統時間精度不夠毫秒,向上取值
如果不再監控某個文件描述符時,可以把pollfd中,fd設置為-1,poll不再監控此pollfd,下次返回時,把revents設置為0。
?
/* server.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #include <poll.h> #include <errno.h> #include "wrap.h"#define MAXLINE 80 #define SERV_PORT 6666 #define OPEN_MAX 1024int main(int argc, char *argv[]) {int i, j, maxi, listenfd, connfd, sockfd;int nready;ssize_t n;char buf[MAXLINE], str[INET_ADDRSTRLEN];socklen_t clilen;struct pollfd client[OPEN_MAX];struct sockaddr_in cliaddr, servaddr;listenfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));Listen(listenfd, 20);client[0].fd = listenfd;client[0].events = POLLRDNORM; /* listenfd監聽普通讀事件 */for (i = 1; i < OPEN_MAX; i++)client[i].fd = -1; /* 用-1初始化client[]里剩下元素 */maxi = 0; /* client[]數組有效元素中最大元素下標 */for ( ; ; ) {nready = poll(client, maxi+1, -1); /* 阻塞 */if (client[0].revents & POLLRDNORM) { /* 有客戶端鏈接請求 */clilen = sizeof(cliaddr);connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);printf("received from %s at PORT %d\n",inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),ntohs(cliaddr.sin_port));for (i = 1; i < OPEN_MAX; i++) {if (client[i].fd < 0) {client[i].fd = connfd; /* 找到client[]中空閑的位置,存放accept返回的connfd */break;}}if (i == OPEN_MAX)perr_exit("too many clients");client[i].events = POLLRDNORM; /* 設置剛剛返回的connfd,監控讀事件 */if (i > maxi)maxi = i; /* 更新client[]中最大元素下標 */if (--nready <= 0)continue; /* 沒有更多就緒事件時,繼續回到poll阻塞 */}for (i = 1; i <= maxi; i++) { /* 檢測client[] */if ((sockfd = client[i].fd) < 0)continue;if (client[i].revents & (POLLRDNORM | POLLERR)) {if ((n = Read(sockfd, buf, MAXLINE)) < 0) {if (errno == ECONNRESET) { /* 當收到 RST標志時 *//* connection reset by client */printf("client[%d] aborted connection\n", i);Close(sockfd);client[i].fd = -1;} else {perr_exit("read error");}} else if (n == 0) {/* connection closed by client */printf("client[%d] closed connection\n", i);Close(sockfd);client[i].fd = -1;} else {for (j = 0; j < n; j++)buf[j] = toupper(buf[j]);Writen(sockfd, buf, n);}if (--nready <= 0)break; /* no more readable descriptors */}}}return 0; }
client
/* client.c */ #include <stdio.h> #include <string.h> #include <unistd.h> #include <netinet/in.h> #include "wrap.h"#define MAXLINE 80 #define SERV_PORT 6666int main(int argc, char *argv[]) {struct sockaddr_in servaddr;char buf[MAXLINE];int sockfd, n;sockfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);servaddr.sin_port = htons(SERV_PORT);Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));while (fgets(buf, MAXLINE, stdin) != NULL) {Write(sockfd, buf, strlen(buf));n = Read(sockfd, buf, MAXLINE);if (n == 0)printf("the other side has been closed.\n");elseWrite(STDOUT_FILENO, buf, n);}Close(sockfd);return 0; }
同樣的包含了wrap.c和wrap.h的文件,放在錯誤分析的那個博客中
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
??? struct pollfd {
??????? int fd; /* 文件描述符 */
??????? short events; /* 監控的事件 */
??????? short revents; /* 監控事件中滿足條件返回的事件 */
??? };
??? POLLIN??????? 普通或帶外優先數據可讀,即POLLRDNORM | POLLRDBAND
??? POLLRDNORM????? 數據可讀
??? POLLRDBAND????? 優先級帶數據可讀
??? POLLPRI ??????? 高優先級可讀數據
??? POLLOUT?? ??? 普通或帶外數據可寫
??? POLLWRNORM????? 數據可寫
??? POLLWRBAND????? 優先級帶數據可寫
??? POLLERR ????? 發生錯誤
??? POLLHUP ??????? 發生掛起
??? POLLNVAL ?????? 描述字不是一個打開的文件
?
??? nfds ?????????? 監控數組中有多少文件描述符需要被監控
?
??? timeout ??????? 毫秒級等待
??????? -1:阻塞等,#define INFTIM -1 ?????????????? Linux中沒有定義此宏
??????? 0:立即返回,不阻塞進程
??????? >0:等待指定毫秒數,如當前系統時間精度不夠毫秒,向上取值
?