您好,登錄后才能下訂單哦!
這篇文章主要介紹“socket編程中poll怎么使用”,在日常操作中,相信很多人在socket編程中poll怎么使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”socket編程中poll怎么使用”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
一. 關于poll
對于IO復用模型,其優點無疑是免去了對一個個IO事件就緒的等待,轉而代之的是同時對多個IO數據的檢測,當檢測等待的事件中至少有一個就緒的時候,就會返回告訴用戶進程“已經有數據準備好了,快看看是哪個趕緊處理”,而對于IO復用的實現,除了可以用select函數,另外一個函數仍然支持這種復用IO模型,就是poll函數;
二. poll函數的用法
雖然同樣是對多個IO事件進行檢測等待,但poll和select多少還是有些不同的:
函數參數中,
先來說nfds,這個是指當前需要關心的文件描述符的個數;
timeout同樣是設置超時時間,只是和select的timeout是一個結構體不一樣,這里只是一個整型類型,且含義是毫秒;
而fds是一個結構體指針,如下:
結構體中,
fd表示所要關心的文件描述符;
events表示該文件描述符所關心的事件,這是一個輸入型參數,要告訴操作系統這個文件描述符對應的事件所關心的操作事件是什么,比如讀或寫;
revents是一個輸出型參數,表示當poll返回時告訴用戶什么操作事件是就緒的,比如如果POLLIN是就緒的,那么返回時revent的值就是POLLIN,告訴用戶fd事件的POLLIN是就緒的;
events和revents的值可以為如下:
選項其實不止這三個,只是這里的討論中這三個選項是最常用的;
events設置為POLLIN表示fd所需要讀取數據,而revents若返回POLLIN則表示data已經ready可以讀取了;
同樣,events設置為POLLOUT表示fd所關心數據的寫入,而revents返回POLLOUT則表示寫事件就緒可以進行數據的寫入;
至于POLLPRI,后面的解釋是作為緊急選項來設置的,在TCP協議報文中有個URG的緊急指針是表示先從緊急數據的地方開始讀取,這里也是這個意思;
與select不同的是,reads與writes是輸入輸出參數,我上一篇博客中設置中:
else if(fds[i] > 0 &&\ FD_ISSET(fds[i],&reads)) //正常事件,但是是非監聽時間,也就代表時新建立的new_sock。 { // char buf[1024]; ssize_t s = read(fds[i],buf,sizeof(buf) -1); if(s > 0) { buf[s] = '\0'; // printf("client : %s\n",buf); printf("client : %s",buf); FD_SET(fds[i],&writes); // write(fds[i],buf,sizeof(s)+1); } else if(s == 0) { printf("client quit...\n"); close(fds[i]); fds[i] = -1; } else{} } else{} if(fds[i] > 0&&\ FD_ISSET(fds[i],&writes)) { write(fds[i],buf,sizeof(buf)); }
在獲取讀事件時對將fds[i],設置到寫事件中,而在poll中,讀事件判斷中修改設置為寫事件。需要等待下一次循環,才能夠獲取到寫事件,然后還必須將events屬性在設置回來。
poll與select不同在于描述符存儲方式不同和參數類型不同。
1.結構體數組的管理:當每次有需要關心的描述符時,將其放入結構體中,每次有無效的描述符后,將其描述符置-1,下次poll函數會忽略它。當有新的描述符加入時,從頭遍歷結構體,將為-1的元素設為要關心的描述符事件狀態。切記:當新的描述符加到結構體數組末尾時要更新關心描述符個數,即poll第二個參數。
2.每次調用poll后,結構體元素revents會存儲就緒事件狀態,當每次重新調用poll之前時,系統會自己設置其為0,重新監聽關心事件(不需要用戶重新置0)
3.poll中參數不是輸入,輸出型,因此timeout,struct pollfd *fds參數不需重置,nfds看情況(參照第一點),而select函數是輸入輸出類型,每次調用前需重置。
下面看服務端的代碼,客戶端就不寫了:
#include<poll.h> #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/socket.h> #include<string.h> #include<errno.h> #include<netinet/in.h> #include<arpa/inet.h> #define _BACKLOG_ 5 #define _SIZE_ 64 static void usage (const char *proc) { printf("%s [ip][prot]\n",proc); } static int start(char *ip,int port) { int sock = socket(AF_INET,SOCK_STREAM,0); if(sock < 0) { perror("socket"); exit(1); } int opt = 1; if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)) < 0) { perror("setsockopt"); exit(3); } struct sockaddr_in local; local.sin_family = AF_INET; local.sin_port = htons(port); local.sin_addr.s_addr = inet_addr(ip); if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0) { perror("bind"); exit(2); } if(listen(sock,_BACKLOG_) < 0) { perror("listen"); exit(2); } return sock; } int main(int argc,char* argv[]) { if(argc != 3) { usage(argv[0]); return 1; } int port = atoi(argv[2]); char *ip = argv[1]; int listen_sock = start(ip,port); //pollfd arrays struct pollfd polls[_SIZE_]; int index = 0; int timeout = 5000; //check question time int i = 0; polls[0].fd = listen_sock; polls[0].events = POLLIN; polls[0].revents = 0; ++index; //init polls.fd for(i = 1;i < _SIZE_;++i) { polls[i].fd = -1; } char buf [1024]; ssize_t s = 0; struct sockaddr_in client; socklen_t len = sizeof(client); int done = 0; int max_fd = 1; while(!done) { switch(poll(polls,max_fd,timeout)) { case -1: perror("poll"); break; case 0: printf("timeout\n"); break; default: { size_t i = 0; for(;i<_SIZE_;++i) { if((polls[i].fd == listen_sock) && (polls[i].revents == POLLIN)) { int accept_sock = accept(listen_sock,(struct sockaddr*)&client,&len); if(accept_sock < 0) { perror("accept"); continue; } printf("connet success\n"); for(;i < _SIZE_;++i) { if(polls[i].fd == -1) { polls[i].fd = accept_sock; polls[i].events = POLLIN; ++max_fd; break; } } if(i == _SIZE_) { close(accept_sock); } } else if((polls[i].fd > 0) &&(polls[i].revents == POLLIN) ) { ssize_t size = read(polls[i].fd,buf,sizeof(buf)-1); if(size < 0) { perror("read"); continue; } else if(size == 0) { printf("client close \n"); struct pollfd tmp = polls[i]; polls[i] = polls[max_fd -1]; polls[max_fd -1] = tmp; close(polls[max_fd - 1].fd); polls[max_fd - 1].fd = -1; } else { buf[size] = '\0'; printf("client # %s",buf); polls[i].events = POLLOUT; } } else if(polls[i].fd > 0&& \ polls[i].revents == POLLOUT) { write(polls[i].fd,buf,sizeof(buf)); polls[i].events = POLLIN; } } } break; } } return 0; }
運行結果:
到此,關于“socket編程中poll怎么使用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。