轉(zhuǎn)載:http://blog.csdn.net/dodo_328/article/details/39081183
1.Selet:本質(zhì)上是通過(guò)設(shè)置或者檢查存放fd標(biāo)志位的數(shù)據(jù)結(jié)構(gòu)來(lái)進(jìn)行下一步處理。
?????????????? 缺點(diǎn):1 單個(gè)進(jìn)程可監(jiān)視的fd數(shù)量被限制,因?yàn)槭苊枋龇蟜d_set限制,fd數(shù)量最大不超過(guò)1024;
????????????????????????? 2 需要維護(hù)一個(gè)用來(lái)存放大量fd的數(shù)據(jù)結(jié)構(gòu),這樣會(huì)使得用戶空間和內(nèi)核空間在傳遞該結(jié)構(gòu)時(shí)復(fù)制開(kāi)銷大;
????????????????????????? 3 對(duì)socket進(jìn)行掃描時(shí)是線性掃描;
????????????????????????? 4 Linux的實(shí)現(xiàn)中select返回時(shí)會(huì)將timeout修改為剩余時(shí)間,所以重復(fù)利用timeout需要注意。
函數(shù)原型:int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);
參數(shù):nfds 需要監(jiān)聽(tīng)的最大fd 值加1;
???????????readfds 等待從此集合中的文件描述符中到來(lái)的數(shù)據(jù);
?????????? writefds 等待向此集合中的文件描述符寫入的數(shù)據(jù);
?????????? exceptfds 等待這些文件描述符操作的異常;
?????????? timeout? 超過(guò)此時(shí)間后函數(shù)返回。
返回值:-1? 發(fā)生錯(cuò)誤;
????????????? 0??? 超時(shí);
?????????????num?? 滿足需求的文件描述符數(shù)目。
?
void FD_CLR(int fd,fd_set *set):用來(lái)從文件描述符集合中刪除一個(gè)文件描述符。
void FD_ISSET(int fd, fd_set *set):用來(lái)測(cè)試在這個(gè)文件描述符集合中,此文件描述符是否被觸發(fā)。
void FD_SET(int fd, fd_set *set):用來(lái)將一個(gè)文件描述符設(shè)置到文件描述符集合中去。
void FD_ZERO(fd_set *set):用來(lái)將文件描述符集合清零。
程序?qū)嵗?#xff1a;
[objc]?view plain
?copy #include<stdio.h>?? #include<stdlib.h>?? #include<sys/time.h>?? #include<sys/types.h>?? #include<unistd.h>?? #include<fcntl.h>?? ?? #define?oops(m,x){perror(m);exit(x);}?? void?showdata(charchar?*,int?);?? ?? int?main(int?ac,charchar?*av[])?? {?? ????int?fd1,fd2;?? ????int?max_fd;?? ????fd_set?readfds;?? ????struct?timeval?timeout;?? ????int?retval;?? ?????? ????if(ac?!=?4)?? ????{?? ????????fprintf(stderr,"Usage:%s?file1?file2?timeout\n",*av);?? ????????exit(1);?? ????}?? ?? ????if((fd1?=?open(av[1],O_RDONLY))?==?-1)?? ????????oops("file1?open",2);?? ?? ????if((fd2?=?open(av[2],O_RDONLY))?==?-1)?? ????????oops("file2?open",3);?? ?? ????max_fd?=?1?+?((fd1?>?fd2)?fd1:fd2);?? ?? ????while(1)?? ????{?? ????????FD_ZERO(&readfds);?? ????????FD_SET(fd1,&readfds);?? ????????FD_SET(fd2,&readfds);?? ?? ????????timeout.tv_sec?=?atoi(av[3]);?? ????????timeout.tv_usec?=?0;?? ?? ????????retval?=?select(max_fd,&readfds,NULL,NULL,&timeout);?? ?? ????????if(retval?==?-1)?? ????????????oops("select",4);?? ????????if(retval?>?0)?? ????????{?? ????????????if(FD_ISSET(fd1,&readfds))?? ????????????????showdata(av[1],fd1);?? ????????????if(FD_ISSET(fd2,&readfds))?? ????????????????showdata(av[2],fd2);?? ????????}?? ????????else?? ????????????printf("no?input?after?%d?seconds\n",atoi(av[3]));?? ????}?? }?? ?? void?showdata(charchar?*fname,int?fd)?? {?? ????char?buf[BUFSIZ];?? ????int?n;?? ?? ????printf("%s:",fname);?? ????fflush(stdout);?? ????n?=?read(fd,buf,BUFSIZ);?? ????if(n?==?-1)?? ????????oops(fname,5);?? ????write(1,buf,n);?? ????write(1,"\n",1);?? }??
?
2.Poll:它將用戶傳入的數(shù)組拷貝到內(nèi)核空間,然后查閱每個(gè)fd對(duì)應(yīng)的設(shè)備狀態(tài),如果設(shè)備就緒則在設(shè)備等待隊(duì)列中加入一項(xiàng)并繼續(xù)遍歷,如果遍歷完所有的fd沒(méi)有發(fā)現(xiàn)設(shè)備就緒,則掛起當(dāng)前進(jìn)程,直到設(shè)備就緒或者主動(dòng)超時(shí),被喚醒后,它又要再次遍歷fd,這個(gè)過(guò)程經(jīng)歷了多次無(wú)謂的遍歷。
????????? 優(yōu)點(diǎn):沒(méi)有最大鏈接數(shù)的限制,原因是因?yàn)樗腔阪湵韥?lái)存儲(chǔ)的;不會(huì)修改timeout的值。
????????? 缺點(diǎn):大量的fd數(shù)組被整體復(fù)制于用戶態(tài)和內(nèi)核地址空間之間。
????????? 特點(diǎn):“水平觸發(fā)”:如果報(bào)告fd后,沒(méi)有被處理,那么下次poll時(shí)會(huì)再次報(bào)告該fd。
struct pollfd{
?????? int fd;? //文件描述符
???????short events;? //等待的事件
?????? short? revents; //實(shí)際發(fā)生的事件
}
函數(shù)原型:int poll(struct pollfd? fds[ ], nfds_t nfds,int timeout);
參數(shù):fds[]? 文件描述符以及等待的事件結(jié)構(gòu)數(shù)組;
?????????? nfds? 表示監(jiān)聽(tīng)的fds的長(zhǎng)度;
???????????timeout 超時(shí);
返回值:-1 發(fā)生錯(cuò)誤;
????????????? 0?? 超時(shí);
???????????? num 滿足需求的文件描述符總數(shù)。
events/revents:POLLIN|POLLOUT
程序?qū)嵗?#xff1a;
[objc]?view plain
?copy #include<stdio.h>?? #include<stdlib.h>?? #include<unistd.h>?? #include<poll.h>?? #include<fcntl.h>?? ?? #define?oops(m,x){perror(m);exit(x);}?? ?? void?showdata(charchar?*,int);??? ?? int?main(int?ac,charchar?*av[])?? {?? ????int?timeout,fd1,fd2;?? ????struct?pollfd?poll_array[2];?? ?????? ????int?ret;?? ?? ????if(ac?!=?4)?? ????{?? ????????fprintf(stderr,"Usage:%s?file1?file2?timeout\n",*av);?? ????????exit(1);?? ????}?? ?? ????timeout?=?atoi(av[3]);?? ?? ????if((fd1?=?open(av[1],O_RDONLY))?==?-1)?? ????????oops(av[1],2);?? ????if((fd2?=?open(av[2],O_RDONLY))?==?-1)?? ????????oops(av[2],3);?? ?? ????poll_array[0].fd?=?fd1;?? ????poll_array[0].events?=?POLLIN;?? ????poll_array[1].fd?=?fd2;?? ????poll_array[1].events?=?POLLIN;?? ?? ????while(1)?? ????{?? ????????ret?=?poll(poll_array,2,timeout);?? ?? ????????if(ret?==?-1)?? ????????????oops("poll?error\n",1);?? ????????if(ret?==?0)?? ????????{?? ????????????printf("timeout..\n");?? ????????????continue;?? ????????}?? ?? ????????if(poll_array[0].revents?&?POLLIN)?? ????????{?? ????????????showdata(av[1],fd1);?? ????????}?? ?? ????????if(poll_array[1].revents?&POLLIN)?? ????????????showdata(av[2],fd2);?? ????}?? ????return?0;?? }?? ?? void?showdata(charchar?*fname,int?fd)?? {?? ????char?buf[BUFSIZ];?? ????int?n;?? ?? ????printf("%s:",fname);?? ????fflush(stdout);?? ????n?=?read(fd,buf,BUFSIZ);?? ????printf("n:%d\n",n);?? ????if(n?==?-1)?? ????????oops(fname,4);?? ????write(1,buf,n);?? ????write(1,"\n",1);?? }??
?
3.Epoll:解決了select和poll的幾個(gè)性能上的缺陷
????????????1. 不限制監(jiān)聽(tīng)的描述符個(gè)數(shù),只受進(jìn)程打開(kāi)的描述符總數(shù)的限制;
????????????2. 監(jiān)聽(tīng)性能不隨著監(jiān)聽(tīng)描述符數(shù)的增加而增加,是0(1)的,不再是輪詢描述符來(lái)探測(cè)事件,而是描述符主動(dòng)上報(bào)事件;
????????????3.使用共享內(nèi)存的方式,不在用戶和內(nèi)核之間反復(fù)傳遞監(jiān)聽(tīng)的描述信息;
??????????? 4.返回參數(shù)就是觸發(fā)事件的列表,不再遍歷。
??????????? 注意:1.epoll創(chuàng)建了描述符,最后要close(epfd);
?????????????????????? 2.支持水平和邊緣觸發(fā)。
int epoll_creat(int size)
功能:用來(lái)創(chuàng)建epoll文件描述符。
參數(shù):size 能在epoll上關(guān)注的最大fd數(shù)。
返回值:epfd。
int epoll_ctl(int epfd,int op,int fd, struct epoll_event *event)
功能:控制對(duì)指定的文件描述符執(zhí)行op操作。
參數(shù):epfd? epoll_creat()函數(shù)的返回值。
?????????? op? EPOLL_CTL_ADD(增加)/EPOLL_CTL_DEL(刪除)/EPOLL_CTL_MOD(修改)。
???????????fd?? 文件描述符。
?????????? event? 與fd 相關(guān)聯(lián)的監(jiān)聽(tīng)事件。
struct? epoll_event{
???????????_uint32_t? events;
?????????? epoll_data_t? data;
};
events:EPOLLIN 可讀。
??????????? EPOLLOUT 可寫。
??????????? EPOLLRDHUP 套接口對(duì)端close或shutdown寫,在ET(邊緣)模式下比較有用。
??????????? EPOLLET 邊緣觸發(fā)模式,在描述符狀態(tài)跳變時(shí)才上報(bào)監(jiān)聽(tīng)事件(監(jiān)聽(tīng)默認(rèn)是LT(水平)模式)。
??????????? EPOLLPRI 緊急數(shù)據(jù)可讀。
??????????? EPOLLERR 異常事件。
??????????? EPOLLHUP 掛起。 EPOLLERR 和EPOLLHUP始終由epoll_wait監(jiān)聽(tīng),不需要用戶設(shè)置。
??????????? EPOLLONESHOT? 只一次有效,描述符在觸發(fā)一次事件之后自動(dòng)失效。fd還在繼續(xù)監(jiān)聽(tīng),直到使用EPOLL_CTL_MOD重新激活,設(shè)置新的監(jiān)聽(tīng)事件。
data: 是個(gè)共用體,可以存放和fd綁定的描述符信息。比如ip/port等。
typedef? union? epoll_data{
????????? void *ptr;//存放與fd綁定的信息。
??????????int fd;
????????? _uint32_t? u32;
????????? _uint32_t? u64;
}epoll_data_t;
int epoll_wait(int epfd,struct epoll_event *events,int maxevents, int timeout)
參數(shù):epfd? epoll_creat()的返回值.
?????????? events? 用于回傳待處理事件的數(shù)組,值結(jié)果參數(shù)。
?????????? maxevents? 每次能處理的事件數(shù)。
?????????? timeout? 超時(shí)設(shè)置。
返回值:-1? 發(fā)生錯(cuò)誤;
????????????? 0?? 超時(shí);
???????????? num? 觸發(fā)事件的描述符總數(shù)。
程序?qū)嵗?#xff1a;
[objc]?view plain
?copy #include<stdio.h>?? #include<stdlib.h>?? #include<poll.h>?? #include<unistd.h>?? #include<fcntl.h>?? #include<sys/types.h>?? #include<sys/epoll.h>?? ?? #define?oops(m,x){perror(m);exit(x);}?? #define?MAX_SIZE_EVENT??500?? ?? void?showdata(int?,charchar?*);?? ?? int?main(int?ac?,charchar?*av[])?? {?? ????int?fd1,fd2;?? ????int?time;?? ????int?epfd;?? ????struct?epoll_event?eventList[MAX_SIZE_EVENT];?? ????struct?epoll_event?fd1_event;?? ????struct?epoll_event?fd2_event;?? ????int?ret;?? ????int?n?;?? ?????? ????if(ac?!=?4)?? ????{?? ????????fprintf(stderr,"Usage:%s?file1?file2?timeout\n",*av);?? ????????exit(1);?? ????}?? ?? ????if((fd1?=?open(av[1],O_RDONLY))?==?-1)?? ????????oops("file1?open",2);?? ????if((fd2?=?open(av[2],O_RDONLY))?==?-1)?? ????????oops("file2?open",3);?? ?????? ????time?=?atoi(av[3]);?? ?? ????epfd?=?epoll_create(MAX_SIZE_EVENT);?? ????fd1_event.events?=?EPOLLIN|EPOLLET;?? ????fd1_event.data.fd?=?fd1;?? ????fd1_event.data.ptr?=?av[1];?? ????fd2_event.events?=?EPOLLIN|EPOLLET;?? ????fd2_event.data.fd?=?fd2;?? ????fd2_event.data.ptr?=?av[2];?? ?? ????if(epoll_ctl(epfd,EPOLL_CTL_ADD,fd1,&fd1_event)?<?0)?? ????????oops("fd1_event?epoll?addfail",4);?? ????if(epoll_ctl(epfd,EPOLL_CTL_ADD,fd2,&fd2_event)?<?0)?? ????????oops("fd2_event?epoll?addfail",5);?? ?? ????while(1)?? ????{?? ????????ret?=?epoll_wait(epfd,eventList,MAX_SIZE_EVENT,time);?? ????????if(ret?<?0)?? ????????????oops("epoll?error",6);?? ????????if(ret?==?0)?? ????????{?? ????????????printf("timeout\n");?? ????????}?? ?? ????????for(n?=?0;n?<?ret;?n++)?? ????????{?? ????????????if(eventList[n].events?&?EPOLLERR?||?eventList[n].events?&?EPOLLHUP?||?!(eventList[n].events?&?EPOLLIN))?? ????????????{?? ????????????????printf("epoll?error");?? ????????????????close(epfd);?? ????????????????close(eventList[n].data.fd);?? ????????????????return?-1;?? ????????????}?? ????????????else?if(eventList[n].events?&?EPOLLIN)?? ????????????????showdata(eventList[n].data.fd,eventList[n].data.ptr);?? ????????}?? ?? ????}?? ????close(epfd);?? ????close(fd1);?? ????close(fd2);?? ????return?0;?? }?? ?? void?showdata(int?fd,charchar?*fname)?? {?? ????char?buf[BUFSIZ];?? ????int?n;?? ?? ????printf("%s:",fname);?? ????fflush(stdout);?? ?? ????n?=?read(fd,buf,BUFSIZ);?? ????if(n?==?-1)?? ????????oops("fd?read",6);?? ????write(1,buf,n);?? ????write(1,"\n",1);?? }??
總結(jié)
以上是生活随笔為你收集整理的select、poll、epoll 比较的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。