外包做网站价格,宜家在线设计网站,简单 大气 网站模版,全国做网站的大公司有哪些转载#xff1a;http://blog.csdn.net/dodo_328/article/details/39081183 1.Selet#xff1a;本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。 缺点#xff1a;1 单个进程可监视的fd数量被限制#xff0c;因为受描述符集合fd_set限制#xff0c;fd数量…转载http://blog.csdn.net/dodo_328/article/details/39081183 1.Selet本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。 缺点1 单个进程可监视的fd数量被限制因为受描述符集合fd_set限制fd数量最大不超过1024 2 需要维护一个用来存放大量fd的数据结构这样会使得用户空间和内核空间在传递该结构时复制开销大 3 对socket进行扫描时是线性扫描; 4 Linux的实现中select返回时会将timeout修改为剩余时间所以重复利用timeout需要注意。 函数原型int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout); 参数nfds 需要监听的最大fd 值加1 readfds 等待从此集合中的文件描述符中到来的数据 writefds 等待向此集合中的文件描述符写入的数据 exceptfds 等待这些文件描述符操作的异常 timeout 超过此时间后函数返回。 返回值-1 发生错误 0 超时 num 满足需求的文件描述符数目。 void FD_CLR(int fd,fd_set *set)用来从文件描述符集合中删除一个文件描述符。 void FD_ISSET(int fd, fd_set *set)用来测试在这个文件描述符集合中此文件描述符是否被触发。 void FD_SET(int fd, fd_set *set)用来将一个文件描述符设置到文件描述符集合中去。 void FD_ZERO(fd_set *set)用来将文件描述符集合清零。 程序实例 [objc] view plain copy #includestdio.h #includestdlib.h #includesys/time.h #includesys/types.h #includeunistd.h #includefcntl.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:它将用户传入的数组拷贝到内核空间然后查阅每个fd对应的设备状态如果设备就绪则在设备等待队列中加入一项并继续遍历如果遍历完所有的fd没有发现设备就绪则挂起当前进程直到设备就绪或者主动超时被唤醒后它又要再次遍历fd,这个过程经历了多次无谓的遍历。 优点没有最大链接数的限制原因是因为它是基于链表来存储的不会修改timeout的值。 缺点大量的fd数组被整体复制于用户态和内核地址空间之间。 特点“水平触发”如果报告fd后没有被处理那么下次poll时会再次报告该fd。 struct pollfd{ int fd; //文件描述符 short events; //等待的事件 short revents; //实际发生的事件 } 函数原型int poll(struct pollfd fds[ ], nfds_t nfds,int timeout); 参数fds[] 文件描述符以及等待的事件结构数组 nfds 表示监听的fds的长度 timeout 超时 返回值-1 发生错误 0 超时 num 满足需求的文件描述符总数。 events/reventsPOLLIN|POLLOUT 程序实例 [objc] view plain copy #includestdio.h #includestdlib.h #includeunistd.h #includepoll.h #includefcntl.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 i; 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的几个性能上的缺陷 1. 不限制监听的描述符个数只受进程打开的描述符总数的限制 2. 监听性能不随着监听描述符数的增加而增加是0(1)的不再是轮询描述符来探测事件而是描述符主动上报事件 3.使用共享内存的方式不在用户和内核之间反复传递监听的描述信息 4.返回参数就是触发事件的列表不再遍历。 注意1.epoll创建了描述符最后要close(epfd); 2.支持水平和边缘触发。 int epoll_creat(int size) 功能用来创建epoll文件描述符。 参数size 能在epoll上关注的最大fd数。 返回值epfd。 int epoll_ctl(int epfd,int op,int fd, struct epoll_event *event) 功能控制对指定的文件描述符执行op操作。 参数epfd epoll_creat()函数的返回值。 op EPOLL_CTL_ADD(增加)/EPOLL_CTL_DEL(删除)/EPOLL_CTL_MOD(修改)。 fd 文件描述符。 event 与fd 相关联的监听事件。 struct epoll_event{ _uint32_t events; epoll_data_t data; }; events:EPOLLIN 可读。 EPOLLOUT 可写。 EPOLLRDHUP 套接口对端close或shutdown写在ET边缘模式下比较有用。 EPOLLET 边缘触发模式在描述符状态跳变时才上报监听事件监听默认是LT水平模式。 EPOLLPRI 紧急数据可读。 EPOLLERR 异常事件。 EPOLLHUP 挂起。 EPOLLERR 和EPOLLHUP始终由epoll_wait监听不需要用户设置。 EPOLLONESHOT 只一次有效描述符在触发一次事件之后自动失效。fd还在继续监听直到使用EPOLL_CTL_MOD重新激活设置新的监听事件。 data: 是个共用体可以存放和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) 参数epfd epoll_creat()的返回值. events 用于回传待处理事件的数组值结果参数。 maxevents 每次能处理的事件数。 timeout 超时设置。 返回值-1 发生错误 0 超时 num 触发事件的描述符总数。 程序实例 [objc] view plain copy #includestdio.h #includestdlib.h #includepoll.h #includeunistd.h #includefcntl.h #includesys/types.h #includesys/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); }