這篇文章主要介紹“socket編程中poll怎么使用”,在日常操作中,相信很多人在socket編程中poll怎么使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”socket編程中poll怎么使用”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),中山企業(yè)網(wǎng)站建設(shè),中山品牌網(wǎng)站建設(shè),網(wǎng)站定制,中山網(wǎng)站建設(shè)報價,網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,中山網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強企業(yè)競爭力。可充分滿足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網(wǎng)站。
一. 關(guān)于poll
對于IO復(fù)用模型,其優(yōu)點無疑是免去了對一個個IO事件就緒的等待,轉(zhuǎn)而代之的是同時對多個IO數(shù)據(jù)的檢測,當(dāng)檢測等待的事件中至少有一個就緒的時候,就會返回告訴用戶進程“已經(jīng)有數(shù)據(jù)準備好了,快看看是哪個趕緊處理”,而對于IO復(fù)用的實現(xiàn),除了可以用select函數(shù),另外一個函數(shù)仍然支持這種復(fù)用IO模型,就是poll函數(shù);
二. poll函數(shù)的用法
雖然同樣是對多個IO事件進行檢測等待,但poll和select多少還是有些不同的:
函數(shù)參數(shù)中,
先來說nfds,這個是指當(dāng)前需要關(guān)心的文件描述符的個數(shù);
timeout同樣是設(shè)置超時時間,只是和select的timeout是一個結(jié)構(gòu)體不一樣,這里只是一個整型類型,且含義是毫秒;
而fds是一個結(jié)構(gòu)體指針,如下:
結(jié)構(gòu)體中,
fd表示所要關(guān)心的文件描述符;
events表示該文件描述符所關(guān)心的事件,這是一個輸入型參數(shù),要告訴操作系統(tǒng)這個文件描述符對應(yīng)的事件所關(guān)心的操作事件是什么,比如讀或?qū)懀?/p>
revents是一個輸出型參數(shù),表示當(dāng)poll返回時告訴用戶什么操作事件是就緒的,比如如果POLLIN是就緒的,那么返回時revent的值就是POLLIN,告訴用戶fd事件的POLLIN是就緒的;
events和revents的值可以為如下:
選項其實不止這三個,只是這里的討論中這三個選項是最常用的;
events設(shè)置為POLLIN表示fd所需要讀取數(shù)據(jù),而revents若返回POLLIN則表示data已經(jīng)ready可以讀取了;
同樣,events設(shè)置為POLLOUT表示fd所關(guān)心數(shù)據(jù)的寫入,而revents返回POLLOUT則表示寫事件就緒可以進行數(shù)據(jù)的寫入;
至于POLLPRI,后面的解釋是作為緊急選項來設(shè)置的,在TCP協(xié)議報文中有個URG的緊急指針是表示先從緊急數(shù)據(jù)的地方開始讀取,這里也是這個意思;
與select不同的是,reads與writes是輸入輸出參數(shù),我上一篇博客中設(shè)置中:
else if(fds[i] > 0 &&\ FD_ISSET(fds[i],&reads)) //正常事件,但是是非監(jiān)聽時間,也就代表時新建立的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],設(shè)置到寫事件中,而在poll中,讀事件判斷中修改設(shè)置為寫事件。需要等待下一次循環(huán),才能夠獲取到寫事件,然后還必須將events屬性在設(shè)置回來。
poll與select不同在于描述符存儲方式不同和參數(shù)類型不同。
1.結(jié)構(gòu)體數(shù)組的管理:當(dāng)每次有需要關(guān)心的描述符時,將其放入結(jié)構(gòu)體中,每次有無效的描述符后,將其描述符置-1,下次poll函數(shù)會忽略它。當(dāng)有新的描述符加入時,從頭遍歷結(jié)構(gòu)體,將為-1的元素設(shè)為要關(guān)心的描述符事件狀態(tài)。切記:當(dāng)新的描述符加到結(jié)構(gòu)體數(shù)組末尾時要更新關(guān)心描述符個數(shù),即poll第二個參數(shù)。
2.每次調(diào)用poll后,結(jié)構(gòu)體元素revents會存儲就緒事件狀態(tài),當(dāng)每次重新調(diào)用poll之前時,系統(tǒng)會自己設(shè)置其為0,重新監(jiān)聽關(guān)心事件(不需要用戶重新置0)
3.poll中參數(shù)不是輸入,輸出型,因此timeout,struct pollfd *fds參數(shù)不需重置,nfds看情況(參照第一點),而select函數(shù)是輸入輸出類型,每次調(diào)用前需重置。
下面看服務(wù)端的代碼,客戶端就不寫了:
#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; }
運行結(jié)果:
到此,關(guān)于“socket編程中poll怎么使用”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
當(dāng)前名稱:socket編程中poll怎么使用
分享路徑:http://www.rwnh.cn/article48/jsdeep.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作、虛擬主機、企業(yè)建站、手機網(wǎng)站建設(shè)、微信小程序、網(wǎng)站排名
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)