函數(shù)原型:
創(chuàng)新互聯(lián)是專業(yè)的奉賢網(wǎng)站建設(shè)公司,奉賢接單;提供成都做網(wǎng)站、成都網(wǎng)站建設(shè),網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行奉賢網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!函數(shù)說明:該函數(shù)允許進(jìn)程指示內(nèi)核等待多個(gè)事件中的任何一個(gè)發(fā)生,并只在有一個(gè)或多個(gè)事件發(fā)生或經(jīng)歷一段指定的時(shí)間后才喚醒它。
參數(shù)說明:
fds:是一個(gè)struct pollfd結(jié)構(gòu)類型的數(shù)組,用于存放需要檢測其狀態(tài)的Socket描述符;
每當(dāng)調(diào)用這個(gè)函數(shù)之后,系統(tǒng)不會清空這個(gè)數(shù)組,操作起來比較方便;特別是對于socket連接比較多的情況下,在一定程度上可以提高處理的效率;這一點(diǎn)與select()函數(shù)不同,調(diào)用select()函數(shù)之后,select()函數(shù)會清空它所檢測的socket描述符集合,導(dǎo)致每次調(diào)用select()之前都必須把socket描述符重新加入到待檢測的集合中;因此,select()函數(shù)適合于只檢測一個(gè)socket描述符的情況,而poll()函數(shù)適合于大量socket描述符的情況;
nfds:nfds_t類型的參數(shù),用于標(biāo)記數(shù)組fds中的結(jié)構(gòu)體元素的總數(shù)量;
timeout:是poll函數(shù)阻塞的時(shí)間,單位:毫秒;
如果timeout==0,那么poll() 函數(shù)立即返回而不阻塞
如果timeout==INFTIM,即負(fù)數(shù),那么poll() 函數(shù)會一直阻塞下去,直到所檢測的socket描述符上的感興趣的事件發(fā)生是才返回,如果感興趣的事件永遠(yuǎn)不發(fā)生,那么poll()就會永遠(yuǎn)阻塞下去;
poll()函數(shù)會以輪詢方式在timeout所指定的毫秒時(shí)間長度之后返回
返回值:
>0:數(shù)組fds中準(zhǔn)備好讀、寫或出錯(cuò)狀態(tài)的那些socket描述符的總數(shù)量;
==0:數(shù)組fds中沒有任何socket描述符準(zhǔn)備好讀、寫,或出錯(cuò);此時(shí)poll超時(shí),超時(shí)時(shí)間是timeout毫秒
-1: poll函數(shù)調(diào)用失敗,同時(shí)會自動設(shè)置全局變量errno;
struct pollfd中event的設(shè)置參數(shù):
實(shí)現(xiàn)IO復(fù)用:關(guān)心輸入輸出條件就緒
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<poll.h> int main() { struct pollfd fds[2]; fds[0].fd=0; fds[0].events=POLLIN; fds[0].revents=0; fds[1].fd=1; fds[1].events=POLLOUT; fds[1].revents=0; char buf[1024]; ssize_t _s; int i=0; int timeout=5000; while(1) { timeout=5000; switch(poll(fds,2,timeout)) { case -1://error perror("poll"); break; case 0://timeout printf("time out\n"); break; default: { for(i=0;i<2;++i) { if(fds[i].fd==0&&fds[i].revents&POLLIN) { _s=read(0,buf,sizeof(buf)-1); if(_s>0) { buf[_s]='\0'; if(strncmp(buf,"quit",4)==0) { close(fds[i].fd); exit(0); } printf("echo:%s",buf); } //fds[i].revents=0;//not need } // else if(fds[i].fd==1&&fds[i].revents&&POLLOUT) // { // strcpy(buf,"hello"); // printf("echo: %s",buf); // fds[i].revents=0;//not need // } } } break; } } return 0; }
運(yùn)行截圖:
TCP通信:監(jiān)聽socket
server:
創(chuàng)建監(jiān)聽套接字并初始化:調(diào)用socket,bind,listen,唯一描述符是監(jiān)聽描述符初始化數(shù)據(jù)結(jié)構(gòu)。
阻塞于select:select等待某個(gè)事件發(fā)生或新客戶連接的建立或是數(shù)據(jù),F(xiàn)IN或RST的到達(dá)。
accept新連接
如果監(jiān)聽套接字變?yōu)榭勺x,那么已建立一個(gè)新的連接,我們調(diào)用accept并更新相應(yīng)數(shù)據(jù)結(jié)構(gòu)。使用fds數(shù)組中第一個(gè)未用項(xiàng)記錄這個(gè)已連接描述符。
檢查現(xiàn)有連接
對于每個(gè)現(xiàn)有客戶連接,我們要測試其描述符是否在select返回描述符集中,如果是就從該客戶讀取一行文本,并回顯,輸出。如果該客戶關(guān)閉了連接,那么read將返回0,更新數(shù)據(jù)結(jié)構(gòu)。
poll與select不同在于描述符存儲方式不同和參數(shù)類型不同。
1.結(jié)構(gòu)體數(shù)組的管理:當(dāng)每次有需要關(guān)心的描述符時(shí),將其放入結(jié)構(gòu)體中,每次有無效的描述符后,將其描述符置-1,下次poll函數(shù)會忽略它。當(dāng)有新的描述符加入時(shí),從頭遍歷結(jié)構(gòu)體,將為-1的元素設(shè)為要關(guān)心的描述符事件狀態(tài)。切記:當(dāng)新的描述符加到結(jié)構(gòu)體數(shù)組末尾時(shí)要更新關(guān)心描述符個(gè)數(shù),即poll第二個(gè)參數(shù)。
2.每次調(diào)用poll后,結(jié)構(gòu)體元素revents會存儲就緒事件狀態(tài),當(dāng)每次重新調(diào)用poll之前時(shí),系統(tǒng)會自己設(shè)置其為0,重新監(jiān)聽關(guān)心事件(不需要用戶重新置0)
3.poll中參數(shù)不是輸入,輸出型,因此timeout,struct pollfd *fds參數(shù)不需重置,nfds看情況(參照第一點(diǎn)),而select函數(shù)是輸入輸出類型,每次調(diào)用前需重置。
//server:最終版 include<stdio.h> #include<sys/socket.h> #include<sys/types.h> #include<netinet/in.h> #include<arpa/inet.h> #include<stdlib.h> #include<poll.h> #include<string.h> #include<errno.h> #define _BACKLOG_ 5 #define _SIZE_ 64 static void usage(const char* proc) { printf("%s [ip][port]\n",proc); } static int start(char* ip,int port) { //1.create a socket int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(1); } //2.bind 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); } //3.set listen state if(listen(sock,_BACKLOG_)<0) { perror("listen"); exit(3); } 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]; //listen_sock_fd int listen_sock=start(_ip,_port); struct pollfd polls[_SIZE_];//struct pollfd arrays int index=0;//effective fdnum int timeout=5000;//millseconds int i=0;//index polls[0].fd=listen_sock; polls[0].events=POLLIN; polls[0].revents=0; int max_num=1; for(i=1;i<_SIZE_;++i) { polls[i].fd=-1; } char buf[1024]; ssize_t _s=0; struct sockaddr_in remote;//accept socklen_t len=sizeof(remote); while(1) { //new start //timeout=5000; switch(poll(polls,max_num,timeout)) { case 0://timeout printf("time out...\n"); break; case -1://error perror("poll"); break; default://normal { for(i=0;i<max_num;++i) { if(polls[i].fd==listen_sock&&(polls[i].revents&\ POLLIN)) { printf("get a connect\n"); int new_sock=accept(listen_sock,\ (struct sockaddr*)&remote,&len); if(new_sock<0) { perror("accept"); continue; } int j=1;//0 is listensock for(;j<_SIZE_;++j) { if(polls[j].fd==-1) { polls[j].fd=new_sock; polls[j].events=POLLIN; polls[j].revents=0; break; } } if(j==_SIZE_) { printf("full"); close(new_sock); return -1; } if(j==max_num)//加入的是max_num為下標(biāo)的位置,即最后 max_num+=1; } else if(polls[i].fd>0&&(polls[i].revents&\ POLLIN))//read ready { _s=read(polls[i].fd,buf,sizeof(buf)-1); if(_s>0) { buf[_s]='\0'; printf("client: %s",buf); write(polls[i].fd,buf,strlen(buf)); polls[i].revents=0;//not need } else if(_s==0)//client close { close(polls[i].fd); polls[i].fd=-1; printf("client is close\n"); } } else {} } } break; } } for(i=0;i<_SIZE_;++i) { if(polls[i].fd!=-1) close(polls[i].fd); } return 0; } //server:優(yōu)質(zhì)版 #include<stdio.h> #include<sys/socket.h> #include<sys/types.h> #include<netinet/in.h> #include<arpa/inet.h> #include<stdlib.h> #include<poll.h> #include<string.h> #include<errno.h> #define _BACKLOG_ 5 #define _SIZE_ 64 static void usage(const char* proc) { printf("%s [ip][port]\n",proc); } static int start(char* ip,int port) { //1.create a socket int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(1); } //2.bind 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); } //3.set listen state if(listen(sock,_BACKLOG_)<0) { perror("listen"); exit(3); } 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]; //listen_sock_fd int listen_sock=start(_ip,_port); struct pollfd polls[_SIZE_];//struct pollfd arrays int index=0;//effective fdnum int timeout=5000;//millseconds int i=0;//index polls[0].fd=listen_sock; polls[0].events=POLLIN; polls[0].revents=0; ++index; for(i=1;i<_SIZE_;++i) { polls[i].fd=-1; } char buf[1024]; ssize_t _s=0; struct sockaddr_in remote;//accept socklen_t len=sizeof(remote); while(1) { //new start timeout=5000; int j=index; i=0; //消除struct pollfd中已不關(guān)心的描述符:前移,得到有效的最后一個(gè)元素下標(biāo) while(i<j) { while(i<j&&polls[i].fd!=-1)//從前面數(shù)第一個(gè)無效的 ++i; while(i<j&&polls[j].fd==-1)//從后面數(shù)第一個(gè)有效的 --j; if(i<j)//復(fù)制fd { polls[i].fd=polls[j].fd; polls[i].events=POLLIN;//可不需要,因?yàn)閑vent參數(shù)不發(fā)生變化,本程序只監(jiān)聽讀事件 polls[index].revents=0; } } index=i; //printf("%d",index); //須保證polls是有序的 switch(poll(polls,index,timeout))//index表明最后一個(gè)關(guān)心的描述符在數(shù)組中下標(biāo)+1=個(gè)數(shù) { case 0://timeout printf("time out...\n"); break; case -1://error perror("poll"); break; default://normal { for(i=0;i<index;++i) { if(polls[i].fd==listen_sock&&(polls[i].revents&\ POLLIN)) { printf("get a connect\n"); int new_sock=accept(listen_sock,\ (struct sockaddr*)&remote,&len); if(new_sock<0) { perror("accept"); continue; } if(index==_SIZE_) { printf("full"); close(new_sock); return -1; } polls[index].fd=new_sock; polls[index].events=POLLIN; polls[index].revents=0; ++index; } else if(polls[i].fd>0&&(polls[i].revents&\ POLLIN))//read ready { _s=read(polls[i].fd,buf,sizeof(buf)-1); if(_s>0) { buf[_s]='\0'; printf("client: %s",buf); write(polls[i].fd,buf,strlen(buf)); polls[i].revents=0; } else if(_s==0)//client close { close(polls[i].fd); polls[i].fd=-1; printf("client is close\n"); } } else {} } } break; } } for(i=0;i<_SIZE_;++i) { if(polls[i].fd!=-1) close(polls[i].fd); } return 0; } //仿select版,用輔助數(shù)組存儲,沒有利用poll結(jié)構(gòu)體的優(yōu)點(diǎn),event不清空,開銷大 int main(int argc,char* argv[]) { if(argc!=3) { usage(argv[0]); return 1; } int _port=atoi(argv[2]); char* _ip=argv[1]; //listen_sock_fd int listen_sock=start(_ip,_port); struct pollfd polls[_SIZE_];//struct pollfd arrays int index=0;//effective fdnum int timeout=5000;//millseconds int i=0;//index int fds[_SIZE_]; fds[0]=listen_sock; for(i=1;i<_SIZE_;++i) { fds[i]=-1; } char buf[1024]; ssize_t _s=0; struct sockaddr_in remote;//accept socklen_t len=sizeof(remote); while(1) { index=0;//new start timeout=5000; for(i=0;i<_SIZE_;++i) { polls[i].fd=-1; } for(i=0;i<_SIZE_;++i) { if(fds[i]!=-1) { polls[index].fd=fds[i]; polls[index].events=POLLIN; polls[index].revents=0; ++index; } } switch(poll(polls,index,timeout)) { case 0://timeout printf("time out...\n"); break; case -1://error perror("poll"); break; default://normal { for(i=0;i<index;++i) { if(polls[i].fd==listen_sock&&(polls[i].revents&\ POLLIN)) { printf("get a connect\n"); int new_sock=accept(listen_sock,\ (struct sockaddr*)&remote,&len); if(new_sock<0) { perror("accept"); continue; } int j; for(j=0;j<_SIZE_;++j) { if(fds[j]==-1) { fds[j]=new_sock; break; } } if(j==_SIZE_) { printf("full"); close(new_sock); return -1; } polls[i].revents=0;//reset } else if(polls[i].fd>0&&(polls[i].revents&\ POLLIN))//read ready { _s=read(polls[i].fd,buf,sizeof(buf)-1); if(_s>0) { buf[_s]='\0'; printf("client: %s",buf); write(polls[i].fd,buf,strlen(buf)); } else if(_s==0)//client close { close(polls[i].fd); int j; for(j=0;j<_SIZE_;++j) { if(fds[j]==polls[i].fd) { fds[j]=-1; break; } } printf("client is close\n"); } } else {} } } break; } } for(i=0;i<_SIZE_;++i) { if(fds[i]!=-1) close(fds[i]); } return 0; } //client: #include<stdio.h> #include<stdlib.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<arpa/inet.h> #include<netinet/in.h> #include<string.h> void Usage(const char* proc) { printf("%s [ip][port]",proc); } int main(int argc,char* argv[]) { if(argc!=3) { Usage(argv[0]); return 1; } int client_sock=socket(AF_INET,SOCK_STREAM,0); if(client_sock<0) { perror("socket"); return 1; } struct sockaddr_in client; client.sin_family=AF_INET; client.sin_port=htons(atoi(argv[2])); client.sin_addr.s_addr=inet_addr(argv[1]); char buf[1024]; ssize_t _s; if(connect(client_sock,(struct sockaddr*)&client,sizeof(client))<0) { perror("connection"); return 2; } while(1) { printf("please enter:\n"); _s=read(0,buf,sizeof(buf)-1); if(_s>0) buf[_s]='\0'; if(strncmp(buf,"quit",4)==0) { printf("client is quit\n"); break; } write(client_sock,buf,_s); _s=read(client_sock,buf,sizeof(buf)-1); if(_s>0) { buf[_s]='\0'; printf("server->client: %s",buf); } } close(client_sock); return 0; }
運(yùn)行截圖:
創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務(wù)器,動態(tài)BGP最優(yōu)骨干路由自動選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨(dú)有T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動現(xiàn)已開啟,新人活動云服務(wù)器買多久送多久。
分享標(biāo)題:poll實(shí)現(xiàn)IO復(fù)用,TCP通信-創(chuàng)新互聯(lián)
標(biāo)題來源:http://muchs.cn/article42/doohec.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站建設(shè)、移動網(wǎng)站建設(shè)、ChatGPT、電子商務(wù)、全網(wǎng)營銷推廣、網(wǎng)站策劃
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容