Linux 高效能伺服器程式設計——I/O複用 poll
阿新 • • 發佈:2018-12-15
一:poll系統呼叫
同select相似,也是在指定時間內輪詢一定數量的檔案描述符,以測試其中是否有就緒者。
二:poll函式
1.函式原型:
#include<poll.h>
int poll(struct pollfd* fds,nfds_t nfds,int timeout);
2.函式引數:
先來了解一下struct pollfd這個結構體
struct pollfd { int fd; //檔案描述符 short events; //註冊的事件 short revents; //實際發生的事件,由核心填充。 } /*其中fd成員指定檔案描述符;events成員告訴poll監聽fa上的那些事件,它是一系列事件的按位或; revents則有核心修改,以通知應用程式fd上實際發生了那些事件。*/
①fds: | pollfd結構型別的陣列,指定我們所有感興趣的檔案描述符上發生的可讀,可寫,異常等事件。 |
②ndfs: | 指定被監聽事件集合fds的大小。(其型別位:typedef unsigned long int nfds_t;) |
③timeout: | 設定超時時間,單位毫秒。 -1:poll將永遠阻塞 0:poll呼叫將立即返回。 |
三:邏輯思想
四:測試程式碼
伺服器端:
//poll.c #define _GNU_SOURCE #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include<assert.h> #include<stdio.h> #include<unistd.h> #include<string.h> #include<poll.h> #define SIZE 100 void Delete_fd(struct pollfd *fds , int fd) { int i=0; for(;i<SIZE;++i) { if(fds[i].fd == fd) { fds[i].fd = -1; fds[i].events = 0; // fds[i].revents = 0; } } } void Init_fd(struct pollfd *fds) { int i = 0; for(;i<SIZE;++i) { fds[i].fd = -1; fds[i].events = 0; fds[i].revents = 0; } } void Insert_fd(struct pollfd *fds,int fd,short event) { int i= 0 ; for(;i<SIZE;++i) { if(fds[i].fd == -1) { fds[i].fd = fd; fds[i].events = event; break; } } } int main() { int sockfd = socket(AF_INET,SOCK_STREAM,0); assert(sockfd != -1); struct sockaddr_in ser,cli; memset(&ser,0,sizeof(ser)); ser.sin_family = AF_INET; ser.sin_port = htons(6000); ser.sin_addr.s_addr = inet_addr("127.0.0.1"); int res = bind(sockfd,(struct sockaddr*)&ser,sizeof(ser)); assert(res != -1); listen(sockfd,5); struct pollfd fds[SIZE]; Init_fd(fds); Insert_fd(fds,sockfd,POLLIN); while(1) { int n = poll(fds,SIZE,-1); if(n<=0) { printf("poll fail!!!\n"); continue; } int i = 0; for(;i<SIZE;++i) { if(fds[i].fd != -1) { int fd = fds[i].fd; if(fds[i].revents & POLLRDHUP)//這個應該放到前面 { close(fd); Delete_fd(fds,fd); printf("%d: will close\n",fd); } else if(fds[i].revents & POLLIN) { if(fd == sockfd) { int len = sizeof(cli); int c = accept(sockfd,(struct sockaddr*)&cli,&len); if(c<=0) { printf("accept is fail\n"); continue; } Insert_fd(fds,c,POLLIN|POLLRDHUP); } else { char buff[128]={0}; int n =recv(fds[i].fd,buff,127,0); if(n<=0) { close(fds[i].fd); Delete_fd(fds,fds[i].fd); printf("%d: is close\n",fd); } else { printf("%d: %s\n",fd,buff); send(fd,"OK",2,0); } } } } } } close(sockfd); }
客戶端:
#include"../../apue.h" int main() { int sockfd = socket(AF_INET,SOCK_STREAM,0); assert(sockfd != -1); struct sockaddr_in ser; memset(&ser,0,sizeof(ser)); ser.sin_family = AF_INET; ser.sin_port = htons(6000); ser.sin_addr.s_addr = inet_addr("127.0.0.1"); int res = connect(sockfd,(struct sockaddr*)&ser,sizeof(ser)); assert(res != -1); while(1) { printf("please input:\n"); fflush(stdout); char buf[128]={0}; fgets(buf,127,stdin); buf[strlen(buf)-1] = 0; if(strcmp(buf,"end") == 0) { break; } send(sockfd,buf,strlen(buf),0); printf("send is OK\n"); // char recvbuff[128] = {0}; // recv(sockfd,recvbuff,127,0); // printf("%s:\n",recvbuff); } close(sockfd); }