c/c++语言开发共享linux epoll,poll,select

epoll函数用法,还有点poll和select 1,LT的epoll是select和poll函数的改进版。 特点是,读完缓冲区后,如果缓冲区还有内容的话,epoll_wait函数还会返回,直到把缓冲区全部读完。 2,ET的epoll(阻塞) 特点是,读完缓冲区后,不管缓冲区还有没有内容,epoll …


epoll函数用法,还有点poll和select

1,lt的epoll是select和poll函数的改进版。

特点是,读完缓冲区后,如果缓冲区还有内容的话,epoll_wait函数还会返回,直到把缓冲区全部读完。

2,et的epoll(阻塞)

特点是,读完缓冲区后,不管缓冲区还有没有内容,epoll_wait函数都不会再返回,直到对端再一次发送信息过来。估计有的读者朋友会想到用while去读,但是有个致命的问题,因为文件描述符是阻塞的,所以当全部读完后,进程就会阻塞在recv函数那里,就不能够再处理别的连接了。

3,et的epoll(非阻塞),效率最高的使用方法。

特点是,读完缓冲区后,不管缓冲区还有没有内容,epoll_wait函数都不会再返回,直到对端再一次发送信息过来。但是可以事先用fcntl把文件描述符设置成非阻塞的方式,让后用while一直去读,当全部读完后,recv函数也不会阻塞。

et的epoll(非阻塞)的例子:

#include <stdio.h> #include <sys/epoll.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <errno.h>  int main(int argc, char** argv){    int port = atoi(argv[1]);   int lfd = socket(af_inet, sock_stream, 0);    struct sockaddr_in addr;   addr.sin_family = af_inet;   addr.sin_port = htons(port);   addr.sin_addr.s_addr = inaddr_any;    bind(lfd, (struct sockaddr*)&addr, sizeof(addr));   listen(lfd, 5);    int efd = epoll_create(10);    struct epoll_event re;   re.events = epollin;   re.data.fd = lfd;    epoll_ctl(efd, epoll_ctl_add, lfd, &re);    struct epoll_event events[100];      while(1){     int ret = epoll_wait(efd, events, 100, -1);     printf("======================wait=======n");     if(ret == -1){       perror("epoll_wait");       exit(1);     }      for(int i = 0; i < ret; ++i){       if(events[i].data.fd == lfd){         int cfd = accept(lfd, null, null);          int flags = fcntl(cfd, f_getfl);         flags |= o_nonblock;         fcntl(cfd, f_setfl, flags);              struct epoll_event re;         re.events = epollin | epollet;         re.data.fd = cfd;         epoll_ctl(efd, epoll_ctl_add, cfd, &re);         break;       }       char buf[3];        int ret;       while((ret = recv(events[i].data.fd, buf, sizeof buf, 0)) > 0){         write(stdout_fileno, buf, ret);       }              if(ret == 0){         epoll_ctl(efd, epoll_ctl_del, events[i].data.fd, null);         close(events[i].data.fd);         printf("client disconnetn");       }       else if(ret == -1 && errno == eagain){         printf("read overn");         }     }   } }

poll函数例子:

#include <stdio.h> #include <poll.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h>  int main(int argc, char** argv){    int port = atoi(argv[1]);   int lfd = socket(af_inet, sock_stream, 0);    struct sockaddr_in addr;   addr.sin_family = af_inet;   addr.sin_port = htons(port);   addr.sin_addr.s_addr = inaddr_any;    bind(lfd, (struct sockaddr*)&addr, sizeof(addr));   listen(lfd, 5);    struct pollfd pfd[1024];   for(int i = 0; i < 1024; ++i){     pfd[i].fd = -1;   }   pfd[0].fd = lfd;   pfd[0].events = pollin;   nfds_t maxfd = 0;      while(1){     int ret = poll(pfd, maxfd + 1, -1);     printf("--------------poll------n");     if(pfd[0].revents & pollin){       int cfd = accept(lfd, null, null);       for(int i = 0; i < 1024; ++i){         if(pfd[i].fd == -1){           pfd[i].fd = cfd;           pfd[i].events = pollin;           maxfd++;           break;         }       }       continue;     }      for(int i = 0; i <= maxfd; ++i){       if(pfd[i].revents & pollin){         char buf[64];         int ret = recv(pfd[i].fd, buf, sizeof buf, 0);         if(ret == 0){           pfd[i].fd = -1;           close(pfd[i].fd);           printf("client is disconnetn");         }         else{           write(stdout_fileno, buf, ret);         }       }     }         } } 

通过对比epoll和poll的例子可以看出来:

  • epoll不需要事先决定数组的大小。poll需要。
  • epoll内部是用红黑树实现的效率,不会随着连接的增多,而明显的变低。poll是用链表实现的,所以性能随着连接的增多而降低。poll还不能在windows下使用。epoll是跨平台的。
  • 顺便说下,select是用数组实现的,数组的大小由内核代码写死了,就是1024,所以想增大,只能重新编译内核。但是select是在跨平台的。

c/c++ 学习互助qq群:877684253

linux epoll,poll,select

本人微信:xiaoshitou5854

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请点击右边联系管理员删除。

如若转载,请注明出处:https://www.ctvol.com/c-cdevelopment/602864.html

(0)
上一篇 2021年5月11日
下一篇 2021年5月11日

精彩推荐