服务器之poll
poll服務(wù)器方法采用將監(jiān)聽端口用數(shù)組存放起來,這樣就不需要輪詢的監(jiān)聽整個(gè)文件描述符了
#include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout);struct pollfd {int fd; /* 文件描述符 */short events; /* 監(jiān)控的事件 */short revents; /* 監(jiān)控事件中滿足條件返回的事件 */};POLLIN 普通或帶外優(yōu)先數(shù)據(jù)可讀,即POLLRDNORM | POLLRDBANDPOLLRDNORM 數(shù)據(jù)可讀POLLRDBAND 優(yōu)先級(jí)帶數(shù)據(jù)可讀POLLPRI 高優(yōu)先級(jí)可讀數(shù)據(jù)POLLOUT 普通或帶外數(shù)據(jù)可寫POLLWRNORM 數(shù)據(jù)可寫POLLWRBAND 優(yōu)先級(jí)帶數(shù)據(jù)可寫POLLERR 發(fā)生錯(cuò)誤POLLHUP 發(fā)生掛起POLLNVAL 描述字不是一個(gè)打開的文件nfds 監(jiān)控?cái)?shù)組中有多少文件描述符需要被監(jiān)控timeout 毫秒級(jí)等待-1:阻塞等,#define INFTIM -1 Linux中沒有定義此宏0:立即返回,不阻塞進(jìn)程>0:等待指定毫秒數(shù),如當(dāng)前系統(tǒng)時(shí)間精度不夠毫秒,向上取值如果不再監(jiān)控某個(gè)文件描述符時(shí),可以把pollfd中,fd設(shè)置為-1,poll不再監(jiān)控此pollfd,下次返回時(shí),把revents設(shè)置為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監(jiān)聽普通讀事件 */for (i = 1; i < OPEN_MAX; i++)client[i].fd = -1; /* 用-1初始化client[]里剩下元素 */maxi = 0; /* client[]數(shù)組有效元素中最大元素下標(biāo) */for ( ; ; ) {nready = poll(client, maxi+1, -1); /* 阻塞 */if (client[0].revents & POLLRDNORM) { /* 有客戶端鏈接請(qǐng)求 */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; /* 設(shè)置剛剛返回的connfd,監(jiān)控讀事件 */if (i > maxi)maxi = i; /* 更新client[]中最大元素下標(biāo) */if (--nready <= 0)continue; /* 沒有更多就緒事件時(shí),繼續(xù)回到poll阻塞 */}for (i = 1; i <= maxi; i++) { /* 檢測(cè)client[] */if ((sockfd = client[i].fd) < 0)continue;if (client[i].revents & (POLLRDNORM | POLLERR)) {if ((n = Read(sockfd, buf, MAXLINE)) < 0) {if (errno == ECONNRESET) { /* 當(dāng)收到 RST標(biāo)志時(shí) *//* 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的文件,放在錯(cuò)誤分析的那個(gè)博客中
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
??? struct pollfd {
??????? int fd; /* 文件描述符 */
??????? short events; /* 監(jiān)控的事件 */
??????? short revents; /* 監(jiān)控事件中滿足條件返回的事件 */
??? };
??? POLLIN??????? 普通或帶外優(yōu)先數(shù)據(jù)可讀,即POLLRDNORM | POLLRDBAND
??? POLLRDNORM????? 數(shù)據(jù)可讀
??? POLLRDBAND????? 優(yōu)先級(jí)帶數(shù)據(jù)可讀
??? POLLPRI ??????? 高優(yōu)先級(jí)可讀數(shù)據(jù)
??? POLLOUT?? ??? 普通或帶外數(shù)據(jù)可寫
??? POLLWRNORM????? 數(shù)據(jù)可寫
??? POLLWRBAND????? 優(yōu)先級(jí)帶數(shù)據(jù)可寫
??? POLLERR ????? 發(fā)生錯(cuò)誤
??? POLLHUP ??????? 發(fā)生掛起
??? POLLNVAL ?????? 描述字不是一個(gè)打開的文件
?
??? nfds ?????????? 監(jiān)控?cái)?shù)組中有多少文件描述符需要被監(jiān)控
?
??? timeout ??????? 毫秒級(jí)等待
??????? -1:阻塞等,#define INFTIM -1 ?????????????? Linux中沒有定義此宏
??????? 0:立即返回,不阻塞進(jìn)程
??????? >0:等待指定毫秒數(shù),如當(dāng)前系統(tǒng)時(shí)間精度不夠毫秒,向上取值
?
轉(zhuǎn)載于:https://www.cnblogs.com/wanghao-boke/p/11409506.html
總結(jié)
- 上一篇: 索尼4K电视好吗?分辨率怎样?
- 下一篇: Mysql数据库简单使用(二)