免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: wyezl

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

论坛徽章:
0
发表于 2006-08-22 17:53 |显示全部楼层
原帖由 playmud 于 2006-8-22 17:49 发表
tcp正常的断开需要3次或者4次握手确认,如果没有这个确认他就会保持一定的时间。
/proc/sys/net/ipv4/tcp_keepalive_time


我在服务器端处理完请求就close不行吗?

有的死掉的描述符再给它一个小时它也不会释放了,肯定是没close。

论坛徽章:
0
发表于 2006-08-22 18:02 |显示全部楼层
看了lighttpd代码。有了点思路。明天再继续修改。



  1. #include <sys/types.h>

  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <errno.h>
  7. #include <signal.h>
  8. #include <fcntl.h>

  9. #include "fdevent.h"
  10. #include "settings.h"
  11. #include "buffer.h"

  12. #ifdef USE_LINUX_EPOLL
  13. static void fdevent_linux_sysepoll_free(fdevents *ev) {
  14.         close(ev->epoll_fd);
  15.         free(ev->epoll_events);
  16. }

  17. static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) {
  18.         struct epoll_event ep;
  19.        
  20.         if (fde_ndx < 0) return -1;
  21.        
  22.         memset(&ep, 0, sizeof(ep));
  23.        
  24.         ep.data.fd = fd;
  25.         ep.data.ptr = NULL;
  26.        
  27.         if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) {
  28.                 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
  29.                
  30.                 SEGFAULT();
  31.                
  32.                 return 0;
  33.         }
  34.        
  35.        
  36.         return -1;
  37. }

  38. static int fdevent_linux_sysepoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
  39.         struct epoll_event ep;
  40.         int add = 0;
  41.        
  42.         if (fde_ndx == -1) add = 1;
  43.        
  44.         memset(&ep, 0, sizeof(ep));
  45.        
  46.         ep.events = 0;
  47.        
  48.         if (events & FDEVENT_IN)  ep.events |= EPOLLIN;
  49.         if (events & FDEVENT_OUT) ep.events |= EPOLLOUT;

  50.         /**
  51.          *
  52.          * with EPOLLET we don't get a FDEVENT_HUP
  53.          * if the close is delay after everything has
  54.          * sent.
  55.          *
  56.          */
  57.        
  58.         ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */;
  59.        
  60.         ep.data.ptr = NULL;
  61.         ep.data.fd = fd;
  62.        
  63.         if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) {
  64.                 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
  65.                
  66.                 SEGFAULT();
  67.                
  68.                 return 0;
  69.         }
  70.        
  71.         return fd;
  72. }

  73. static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) {
  74.         return epoll_wait(ev->epoll_fd, ev->epoll_events, ev->maxfds, timeout_ms);
  75. }

  76. static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) {
  77.         int events = 0, e;
  78.        
  79.         e = ev->epoll_events[ndx].events;
  80.         if (e & EPOLLIN) events |= FDEVENT_IN;
  81.         if (e & EPOLLOUT) events |= FDEVENT_OUT;
  82.         if (e & EPOLLERR) events |= FDEVENT_ERR;
  83.         if (e & EPOLLHUP) events |= FDEVENT_HUP;
  84.         if (e & EPOLLPRI) events |= FDEVENT_PRI;
  85.        
  86.         return e;
  87. }

  88. static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) {
  89. # if 0
  90.         fprintf(stderr, "%s.%d: %d, %d\n", __FILE__, __LINE__, ndx, ev->epoll_events[ndx].data.fd);
  91. # endif
  92.        
  93.         return ev->epoll_events[ndx].data.fd;
  94. }

  95. static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) {
  96.         size_t i;
  97.        
  98.         UNUSED(ev);

  99.         i = (ndx < 0) ? 0 : ndx + 1;
  100.        
  101.         return i;
  102. }

  103. int fdevent_linux_sysepoll_init(fdevents *ev) {
  104.         ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
  105. #define SET(x) \
  106.         ev->x = fdevent_linux_sysepoll_##x;
  107.        
  108.         SET(free);
  109.         SET(poll);
  110.        
  111.         SET(event_del);
  112.         SET(event_add);
  113.        
  114.         SET(event_next_fdndx);
  115.         SET(event_get_fd);
  116.         SET(event_get_revent);
  117.        
  118.         if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
  119.                 fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
  120.                         __FILE__, __LINE__, strerror(errno));

  121.                 return -1;
  122.         }

  123.         if (-1 == fcntl(ev->epoll_fd, F_SETFD, FD_CLOEXEC)) {
  124.                 fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
  125.                         __FILE__, __LINE__, strerror(errno));

  126.                 close(ev->epoll_fd);

  127.                 return -1;
  128.         }

  129.         ev->epoll_events = malloc(ev->maxfds * sizeof(*ev->epoll_events));

  130.         return 0;
  131. }

  132. #else
  133. int fdevent_linux_sysepoll_init(fdevents *ev) {
  134.         UNUSED(ev);

  135.         fprintf(stderr, "%s.%d: linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
  136.                 __FILE__, __LINE__);
  137.        
  138.         return -1;
  139. }
  140. #endif



复制代码

论坛徽章:
0
发表于 2006-08-22 18:25 |显示全部楼层
原帖由 playmud 于 2006-8-22 17:52 发表
实在找不到原因,你可以把那个默认超时时间设成10几秒或者几十秒。
系统帮你释放掉占用的资源。

哪个默认的超时?

论坛徽章:
0
发表于 2006-08-22 22:36 |显示全部楼层
原帖由 wyezl 于 2006-8-22 17:06 发表
通过观察知道
lrwx------  1 root root 64 Aug 22 16:25 480 -> socket:[34370805]
480这个描述符是死掉。不能回收了。我怎么看它的状态?



# ls -l  /proc/28477/fd/
total 20
lrwx------  1 root  ...


34370805是inode号
cat /proc/net/tcp|grep 34370805   

第2、3项为socket的adress:port


还可以:
netstat -a | grep _pid_
如果照你说只有一个的话就很好分析出是拿一个是那个死掉的。看看他的状态是什么

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2006-08-22 23:15 |显示全部楼层
我写的一个非常简单的epoll服务器,
监听从8000到12999共计5000个端口
预创建4096个线程
主线程用线程锁调度

具体代码见: http://www.cublog.cn/u/17999/showart.php?id=159057

论坛徽章:
0
发表于 2006-08-23 09:48 |显示全部楼层
原帖由 nuclearweapon 于 2006-8-22 22:36 发表


34370805是inode号
cat /proc/net/tcp|grep 34370805   

第2、3项为socket的adress:port


还可以:
netstat -a | grep _pid_
如果照你说只有一个的话就很好分析出是拿一个是那个死掉的。看看他的状 ...


死掉的fd。
lrwx------  1 root root 64 Aug 23 09:37 7 -> socket:[35074112]

#cat /proc/net/tcp|grep 35074112
17392: 4D256CCA:0050 4ACF18DA:0843 01 00000000:00000000 00:00000000 00000000   527        0 35074112 1 f4a71020 3000 0 0 2 -1

netstat -a | grep _pid

这个pid是谁的?
怎么看状态?

论坛徽章:
0
发表于 2006-08-23 12:00 |显示全部楼层
原帖由 wyezl 于 2006-8-23 09:48 发表


死掉的fd。
lrwx------  1 root root 64 Aug 23 09:37 7 -> socket:[35074112]

#cat /proc/net/tcp|grep 35074112
17392: 4D256CCA:0050 4ACF18DA:0843 01 00000000:00000000 00:00000000 00000000   ...



实在对不起是我写错了
应该是
netstat -a| grep port

论坛徽章:
0
发表于 2006-08-23 14:38 |显示全部楼层
time_t cfds[MAXFDS];
time_t  now;
加了一个监视线程。每次accept的时候cfds[cfd]=time(NULL);
close(cfd)的时候 cfds[cfd]=0; 临时解决一下。




void *loop_check(void *p)
{
        int i;
        struct epoll_event ev;
        while(1)
        {
                time(&now);
                for(i=0;i<MAXFDS;i++)
                {
                        if(cfds[i]!=0)
                                if(now-cfds[i]>TIMEOUT)
                                {
                                        printf("cfd=%d timeout.\n",i);

                                        ev.data.fd = i;
                                        if(epoll_ctl(epfd, EPOLL_CTL_DEL, i, &ev)!=0)
                                                printf("can't del epoll.\n");

                                        if(close(i)==0)
                                                cfds[i]=0;
                                        else
                                                printf("can't close cfds.\n");

                                }
                }
                sleep(SLEEPTIME);
        }
        return NULL;
}




60s检查一次。发现这样检查出来的还真不少。
./httpd
cfd=8 timeout.
cfd=11 timeout.
cfd=12 timeout.
cfd=17 timeout.
cfd=21 timeout.
cfd=30 timeout.
cfd=32 timeout.
cfd=51 timeout.
cfd=52 timeout.
cfd=59 timeout.
cfd=60 timeout.
cfd=71 timeout.
cfd=76 timeout.
cfd=7 timeout.
cfd=10 timeout.
cfd=14 timeout.
cfd=15 timeout.
cfd=16 timeout.
cfd=18 timeout.
cfd=20 timeout.
cfd=25 timeout.
cfd=33 timeout.
cfd=36 timeout.
cfd=53 timeout.
cfd=58 timeout.

论坛徽章:
0
发表于 2006-08-23 14:42 |显示全部楼层
原因看来就是我原来想的那样。

论坛徽章:
0
发表于 2006-08-23 15:24 |显示全部楼层
这样做效率低了一些。暂时也没好的办法。
如果用线程池效率也是会有影响。

猜测是,一些fd加入了epoll的监视中,但确没有任何事件触发。
所以就都死到里面了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP