免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 104694 | 回复: 188
打印 上一主题 下一主题

epoll模型的使用及其描述符耗尽问题的探讨 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-08-18 10:39 |只看该作者 |倒序浏览
每次接受新连接的时候,我监视了这几个事件。

EPOLLIN | EPOLLET |  EPOLLERR | EPOLLHUP | EPOLLPRI;

每次有一批事件返回,经过统计  
返回的一批fd数量=出错关闭的fd数量+由EPOLLIN转为EPOLLOUT的fd数量+EPOLLOUT正常处理关闭的fd的数量。 也就是说,每批事件都完全处理,没有遗漏。

观察发现EPOLLET |  EPOLLERR | EPOLLHUP 这3发事件的发生率为0。

但fd却成增大趋势。以前那写较小的fd在经历一段时间后渐渐丢失,不再可用。

请问fd都丢失到哪里去了?

-----------------------------------------------------------------------

后来经常有人写信问我这个问题,我在帖子里回复过,好象帖子太多了,不好找,还是写在这里吧。
单纯靠epoll来管理描述符不泄露几乎是不可能的。
完全解决方案很简单,就是对每个fd设置超时时间,如果超过timeout的时间,这个fd没有活跃过,就close掉。

[ 本帖最后由 wyezl 于 2008-12-13 21:42 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2006-08-18 10:46 |只看该作者
有程序?

论坛徽章:
0
3 [报告]
发表于 2006-08-18 11:10 |只看该作者



  1. /*-------------------------------------------------------------------------------------------------
  2. gcc -o httpd httpd.c -lpthread
  3. author: wyezl
  4. 2006.4.28
  5. ---------------------------------------------------------------------------------------------------*/

  6. #include <sys/socket.h>
  7. #include <sys/epoll.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <fcntl.h>
  11. #include <unistd.h>
  12. #include <stdio.h>
  13. #include <pthread.h>
  14. #include <errno.h>

  15. #define PORT 8888
  16. #define MAXFDS 5000
  17. #define EVENTSIZE 100

  18. #define BUFFER "HTTP/1.1 200 OK\r\nContent-Length: 5\r\nConnection: close\r\nContent-Type: text/html\r\n\r\nHello"

  19. int epfd;
  20. void *serv_epoll(void *p);
  21. void setnonblocking(int fd)
  22. {
  23.     int opts;
  24.     opts=fcntl(fd, F_GETFL);
  25.     if (opts < 0)
  26.     {
  27.           fprintf(stderr, "fcntl failed\n");
  28.           return;
  29.     }
  30.     opts = opts | O_NONBLOCK;
  31.     if(fcntl(fd, F_SETFL, opts) < 0)
  32.     {
  33.           fprintf(stderr, "fcntl failed\n");
  34.           return;
  35.     }
  36.     return;
  37. }

  38. int main(int argc, char *argv[])
  39. {
  40.     int fd, cfd,opt=1;
  41.     struct epoll_event ev;
  42.     struct sockaddr_in sin, cin;
  43.     socklen_t sin_len = sizeof(struct sockaddr_in);
  44.     pthread_t tid;
  45.     pthread_attr_t attr;

  46.     epfd = epoll_create(MAXFDS);
  47.     if ((fd = socket(AF_INET, SOCK_STREAM, 0)) <= 0)
  48.     {
  49.           fprintf(stderr, "socket failed\n");
  50.           return -1;
  51.     }
  52.     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*)&opt, sizeof(opt));

  53.     memset(&sin, 0, sizeof(struct sockaddr_in));
  54.     sin.sin_family = AF_INET;
  55.     sin.sin_port = htons((short)(PORT));
  56.     sin.sin_addr.s_addr = INADDR_ANY;
  57.     if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) != 0)
  58.     {
  59.           fprintf(stderr, "bind failed\n");
  60.           return -1;
  61.     }
  62.     if (listen(fd, 32) != 0)
  63.     {
  64.           fprintf(stderr, "listen failed\n");
  65.           return -1;
  66.     }

  67.     pthread_attr_init(&attr);
  68.     pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
  69.     if (pthread_create(&tid, &attr, serv_epoll, NULL) != 0)
  70.     {
  71.           fprintf(stderr, "pthread_create failed\n");
  72.           return -1;
  73.     }

  74.     while ((cfd = accept(fd, (struct sockaddr *)&cin, &sin_len)) > 0)
  75.     {
  76.           setnonblocking(cfd);
  77.           ev.data.fd = cfd;
  78.           ev.events = EPOLLIN | EPOLLET |  EPOLLERR | EPOLLHUP | EPOLLPRI;
  79.           epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev);
  80.           //printf("connect from %s\n",inet_ntoa(cin.sin_addr));
  81.           //printf("cfd=%d\n",cfd);
  82.     }

  83.     if (fd > 0)
  84.           close(fd);
  85.     return 0;
  86. }

  87. void *serv_epoll(void *p)
  88. {
  89.     int i, ret, cfd, nfds;;
  90.     struct epoll_event ev,events[EVENTSIZE];
  91.     char buffer[512];

  92.     while (1)
  93.     {
  94.           nfds = epoll_wait(epfd, events, EVENTSIZE , -1);
  95.           //printf("nfds ........... %d\n",nfds);
  96.           for (i=0; i<nfds; i++)
  97.           {
  98.                 if(events[i].events & EPOLLIN)
  99.                 {
  100.                     cfd = events[i].data.fd;
  101.                     ret = recv(cfd, buffer, sizeof(buffer),0);
  102.                     //printf("read ret..........= %d\n",ret);

  103.                     ev.data.fd = cfd;
  104.                     ev.events = EPOLLOUT | EPOLLET;
  105.                     epoll_ctl(epfd, EPOLL_CTL_MOD, cfd, &ev);
  106.                 }
  107.                 else if(events[i].events & EPOLLOUT)
  108.                 {
  109.                     cfd = events[i].data.fd;
  110.                     ret = send(cfd, BUFFER, strlen(BUFFER), 0);
  111.                     //printf("send ret...........= %d\n", ret);

  112.                     ev.data.fd = cfd;
  113.                     epoll_ctl(epfd, EPOLL_CTL_DEL, cfd, &ev);
  114.                   
  115.                     close(cfd);

  116.                 }

  117.                    else
  118.               {
  119.                                
  120.                 cfd = events[i].data.fd;
  121.                 ev.data.fd = cfd;
  122.                 epoll_ctl(epfd, EPOLL_CTL_DEL, cfd, &ev);
  123.                 close(cfd);
  124.                }


  125.           }
  126.     }
  127.     return NULL;
  128. }












复制代码

论坛徽章:
0
4 [报告]
发表于 2006-08-18 11:23 |只看该作者
只要能帮我找出描述符从哪耗尽的就行。
:)

论坛徽章:
0
5 [报告]
发表于 2006-08-18 11:50 |只看该作者
是不是main()中的cfd没有关闭

论坛徽章:
0
6 [报告]
发表于 2006-08-18 12:25 |只看该作者
main中只接受连接,加入监视,不做处理。
估计epoll_ctl 没判断出错,我下午再测试一下。

论坛徽章:
0
7 [报告]
发表于 2006-08-18 13:27 |只看该作者
if(epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev)<0)
                        printf("............................................EPOLL_CTL_ADD error!\n");

if(epoll_ctl(epfd, EPOLL_CTL_MOD, cfd, &ev)<0)
                                                printf(".......................................EPOLL_CTL_MOD error!\n");


修改了两句,但未发现这里的错误输出,估计也不是这的问题。

不知道到底从哪耗尽的,奇怪。

论坛徽章:
0
8 [报告]
发表于 2006-08-18 15:50 |只看该作者
继续顶。。。。。。。。。。。。。。。。

论坛徽章:
0
9 [报告]
发表于 2006-08-18 15:58 |只看该作者
想帮你实验,但程序无法编译

论坛徽章:
0
10 [报告]
发表于 2006-08-19 20:48 |只看该作者
挑挑错吧,说的不对的话,请见谅!
1,    while ((cfd = accept(fd, (struct sockaddr *)&cin, &sin_len)) > 0)
    可够改成
while(1)
cfd = accept(fd, (struct sockaddr *)&cin, &sin_len;
if(cfd>0)
..
2,你是要让客户端发送一次就不再发送了吗?
  1.                 if(events[i].events & EPOLLIN)
  2.                 {
  3.                     cfd = events[i].data.fd;
  4.                     ret = recv(cfd, buffer, sizeof(buffer),0);
  5.                     //printf("read ret..........= %d\n",ret);

  6.                     ev.data.fd = cfd;
  7.                     ev.events = EPOLLOUT | EPOLLET;
  8.                     epoll_ctl(epfd, EPOLL_CTL_MOD, cfd, &ev);
  9.                 }
复制代码

3,将accept事件列入epoll监控的对象
4,对close最好做一个判断
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP