Chinaunix

标题: epoll模型的使用及其描述符耗尽问题的探讨 [打印本页]

作者: wyezl    时间: 2006-08-18 10:39
标题: epoll模型的使用及其描述符耗尽问题的探讨
每次接受新连接的时候,我监视了这几个事件。

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 编辑 ]
作者: 思一克    时间: 2006-08-18 10:46
有程序?
作者: wyezl    时间: 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. }












复制代码

作者: wyezl    时间: 2006-08-18 11:23
只要能帮我找出描述符从哪耗尽的就行。
:)
作者: 思一克    时间: 2006-08-18 11:50
是不是main()中的cfd没有关闭
作者: wyezl    时间: 2006-08-18 12:25
main中只接受连接,加入监视,不做处理。
估计epoll_ctl 没判断出错,我下午再测试一下。
作者: wyezl    时间: 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");


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

不知道到底从哪耗尽的,奇怪。
作者: wyezl    时间: 2006-08-18 15:50
继续顶。。。。。。。。。。。。。。。。
作者: 思一克    时间: 2006-08-18 15:58
想帮你实验,但程序无法编译
作者: playmud    时间: 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最好做一个判断
作者: tysn    时间: 2006-08-20 11:25
accept()之后的epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev);
要改成:if (epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev)<0) close(cfd);
估计就是这里错吧,这几率比较小,
所以出现“fd在经历一段时间后渐渐丢失”

另外还要考虑playmud挑的4点问题,
比如第一点,lz那样写的while好像跟if差不多,
accept也是在很小几率下出错,出错之后程序就退出?

说的不对的话,请指正!
作者: wyezl    时间: 2006-08-20 12:58
原帖由 思一克 于 2006-8-18 15:58 发表
想帮你实验,但程序无法编译


编译没问题,需要linux 2。6以上内核的支持。
作者: wyezl    时间: 2006-08-20 13:10
[quote]



挑挑错吧,说的不对的话,请见谅!
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,你是要让客户端发送一次就不再发送了吗?


CODE:[Copy to clipboard]                if(events[i].events & EPOLLIN)
                {
                    cfd = events[ i ].data.fd;
                    ret = recv(cfd, buffer, sizeof(buffer),0);
                    //printf("read ret..........= %d\n",ret);

                    ev.data.fd = cfd;
                    ev.events = EPOLLOUT | EPOLLET;
                    epoll_ctl(epfd, EPOLL_CTL_MOD, cfd, &ev);
                }
3,将accept事件列入epoll监控的对象
4,对close最好做一个判断





... [/quote]

1,如果描述符已经耗尽,这样判断cfd永远不会成立。所以就让它退出算了。

2,我只取http请求的头信息的第一行。 get  /xxx  http/1.0 做简单分析,其他的都不要了。按照tcp协议的特点,本应该多次读取的,但测试发现,只读一次就能得到我想要的,基本上没出过错。
里面的数据没读完就留那了,会不会对以后的请求造成什么不好的影响?


3,accept是在住线程里跑,加入了epoll有什么好处吗?

4,对close没做判断,这点确实是遗漏了。我得补上。
谢谢你的建议。

[[i] 本帖最后由 wyezl 于 2006-8-20 13:16 编辑 [/i]]
作者: wyezl    时间: 2006-08-20 13:14
原帖由 tysn 于 2006-8-20 11:25 发表
accept()之后的epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev);
要改成:if (epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev)<0) close(cfd);
估计就是这里错吧,这几率比较小,
所以出现“fd在经历一段时间 ...


这一条判断我后来添加了。 但这儿出错几率几乎为0 。


现在仍未发现耗尽的原因。怀疑是不是epoll机制本身有问题呢?
作者: wyezl    时间: 2006-08-21 09:41
继续顶。。。。。。。。。
作者: 思一克    时间: 2006-08-21 09:49
EPOLLIN事件后是不是应该关闭CFD?

我看的,不一定准确,因为无法实验你的程序
作者: wyezl    时间: 2006-08-21 12:14
原帖由 思一克 于 2006-8-21 09:49 发表
EPOLLIN事件后是不是应该关闭CFD?

我看的,不一定准确,因为无法实验你的程序


如果关闭了,以后就不会有EPOLLOUT了。 因为我是接受请求,然后返回所请求的信息。
作者: 思一克    时间: 2006-08-21 12:18
那你把能编译的贴出,我帮你实验。如果你愿意的话
作者: billzhou    时间: 2006-08-21 12:34
不懂  什么是epoll,哪位兄弟给解释一下
作者: wyezl    时间: 2006-08-21 16:47
原帖由 思一克 于 2006-8-21 12:18 发表
那你把能编译的贴出,我帮你实验。如果你愿意的话


我贴出的代码就是能编译的。
请问你用的是什么操作系统? 版本?
这个程序只能在linux上运行,而且内核版本必须在2.6以上。

[ 本帖最后由 wyezl 于 2006-8-21 16:52 编辑 ]
作者: wyezl    时间: 2006-08-21 16:49
思一克是个热心的斑竹,先赞一个。 :)
作者: 精简指令    时间: 2006-08-21 20:12
“但fd却成增大趋势。以前那写较小的fd在经历一段时间后渐渐丢失,不再可用。”

是否已经将FD用光了? 如果没有用光,试着用到最大值,看看是否会重新分配较小的FD
作者: safedead    时间: 2006-08-21 21:52
我没有这么用过epoll

我的程序是仅用epoll弹出发生EPOLIN事件的LISTEN套接字
然后就ACCEPT出客户端连接就交给线程处理了
没有发生过fd耗尽的情况
作者: 思一克    时间: 2006-08-22 08:19
to LZ,

你的模型好象不太对,至少不太好。epoll_wait和ACCEPT的次序?

你在网络上找,有现成的好的。
作者: wyezl    时间: 2006-08-22 09:54
原帖由 safedead 于 2006-8-21 21:52 发表
我没有这么用过epoll

我的程序是仅用epoll弹出发生EPOLIN事件的LISTEN套接字
然后就ACCEPT出客户端连接就交给线程处理了
没有发生过fd耗尽的情况


方便把你的模型大概贴出来看一下吗?
作者: wyezl    时间: 2006-08-22 09:55
原帖由 精简指令 于 2006-8-21 20:12 发表
“但fd却成增大趋势。以前那写较小的fd在经历一段时间后渐渐丢失,不再可用。”

是否已经将FD用光了? 如果没有用光,试着用到最大值,看看是否会重新分配较小的FD


确实用光了。不能分配小的了。
作者: 星之孩子    时间: 2006-08-22 10:06
为何你用epoll还要用多线程
感觉你这个模型怪怪的
作者: wyezl    时间: 2006-08-22 10:32
只开了两个线程。 epoll独占一个。
作者: 星之孩子    时间: 2006-08-22 10:34
多个线程这样用epoll不知道会不会有问题
其实你的应用根本不用多线程
作者: wyezl    时间: 2006-08-22 11:05
原帖由 思一克 于 2006-8-22 08:19 发表
to LZ,

你的模型好象不太对,至少不太好。epoll_wait和ACCEPT的次序?

你在网络上找,有现成的好的。


能把你觉得好的模型共享一下吗?
作者: nuclearweapon    时间: 2006-08-22 11:43
刚才测试了lz的程序。
50个并发,cfd最大达到37然后回落到5。

如上测试多次没有发现cfd有增大的趋势。
所以感觉和内核版本有关系。

测试环境:

kernel 2.6.15
gcc 4.0.3

distribution:ubuntu
作者: wyezl    时间: 2006-08-22 11:47
下面这个模型我也用过。不过效率很底。


#include <iostream>

#include <sys/socket.h>

#include <sys/epoll.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <fcntl.h>

#include <unistd.h>

#include <stdio.h>



#define MAXLINE 10

#define OPEN_MAX 100

#define LISTENQ 20

#define SERV_PORT 5555

#define INFTIM 1000



void setnonblocking(int sock)

{

  int opts;

  opts=fcntl(sock,F_GETFL);

  if(opts<0)

  {

      perror("fcntl(sock,GETFL)");

      exit(1);

  }

  opts = opts|O_NONBLOCK;

  if(fcntl(sock,F_SETFL,opts)<0)

  {

      perror("fcntl(sock,SETFL,opts)");

      exit(1);

  }   

}



int main()

{

  int i, maxi, listenfd, connfd, sockfd,epfd,nfds;

  ssize_t n;

  char line[MAXLINE];

  socklen_t clilen;

  //声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件

  struct epoll_event ev,events[20];

  //生成用于处理accept的epoll专用的文件描述符

  epfd=epoll_create(256);



  struct sockaddr_in clientaddr;

  struct sockaddr_in serveraddr;

  listenfd = socket(AF_INET, SOCK_STREAM, 0);

  //把socket设置为非阻塞方式

  setnonblocking(listenfd);

  //设置与要处理的事件相关的文件描述符

  ev.data.fd=listenfd;

  //设置要处理的事件类型

  ev.events=EPOLLIN|EPOLLET;

  //注册epoll事件

  epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);



  bzero(&serveraddr, sizeof(serveraddr));

  serveraddr.sin_family = AF_INET;



  char *local_addr="200.200.200.204";

  inet_aton(local_addr,&(serveraddr.sin_addr));//htons(SERV_PORT);

  serveraddr.sin_port=htons(SERV_PORT);

  bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));

  listen(listenfd, LISTENQ);



  maxi = 0;

  for ( ; ; ) {

      //等待epoll事件的发生

      nfds=epoll_wait(epfd,events,20,500);

      //处理所发生的所有事件     

      for(i=0;i<nfds;++i)

      {

          if(events[i].data.fd==listenfd)

          {



            connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);

            if(connfd<0){

                perror("connfd<0");

                exit(1);

            }

            setnonblocking(connfd);



            char *str = inet_ntoa(clientaddr.sin_addr);

            std::cout<<"connect from "<_u115 ?tr<<std::endl;

            //设置用于读操作的文件描述符

            ev.data.fd=connfd;

            //设置用于注测的读操作事件

            ev.events=EPOLLIN|EPOLLET;

            //注册ev

            epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);

          }

          else if(events[i].events&EPOLLIN)

          {

            if ( (sockfd = events[i].data.fd) < 0) continue;

            if ( (n = read(sockfd, line, MAXLINE)) < 0) {

                if (errno == ECONNRESET) {



                    close(sockfd);

                    events[i].data.fd = -1;

                } else

                    std::cout<<"readline error"<<std::endl;

            } else if (n == 0) {

                close(sockfd);

                events[i].data.fd = -1;

            }

            //设置用于写操作的文件描述符

            ev.data.fd=sockfd;

            //设置用于注测的写操作事件

            ev.events=EPOLLOUT|EPOLLET;

            //修改sockfd上要处理的事件为EPOLLOUT

            epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);

          }

          else if(events[i].events&EPOLLOUT)

          {   

            sockfd = events[i].data.fd;

            write(sockfd, line, n);

            //设置用于读操作的文件描述符

            ev.data.fd=sockfd;

            //设置用于注测的读操作事件

            ev.events=EPOLLIN|EPOLLET;

            //修改sockfd上要处理的事件为EPOLIN

            epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);

          }



      }



  }

}
作者: wyezl    时间: 2006-08-22 11:50
原帖由 nuclearweapon 于 2006-8-22 11:43 发表
刚才测试了lz的程序。
50个并发,cfd最大达到37然后回落到5。

如上测试多次没有发现cfd有增大的趋势。
所以感觉和内核版本有关系。

测试环境:

kernel 2.6.15
gcc 4.0.3

distribution:ubuntu


50个并发,cfd最大达到37然后回落到5。 是有这样的现象。所以我说是增大趋势。而没有说直线增长。

这也不是你几分钟就能测试出来的。1024个fd也需要一个多小时才能耗尽(大约处理100万请求)。而且是量比较大的线上测试。
作者: nuclearweapon    时间: 2006-08-22 11:57
原帖由 wyezl 于 2006-8-22 11:50 发表


50个并发,cfd最大达到37然后回落到5。 是有这样的现象。所以我说是增大趋势。而没有说直线增长。

这也不是你几分钟就能测试出来的。1024个fd也需要一个多小时才能耗尽(大约处理100万请求)。而且是量比较 ...


你这里说的耗尽是什么意思?

表示Accept不能再接受client了吗?
作者: nuclearweapon    时间: 2006-08-22 12:02
就调试来说,当服务程序挂起的时候
你可以看如下目录:
/proc/your_process_id/fd

看一看有那些fd在被你的进程使用!
作者: 星之孩子    时间: 2006-08-22 12:38
你另外一个模型就是epoll例子的模型吧
凭什么说人家的就效率低了?
作者: wyezl    时间: 2006-08-22 13:10
原帖由 星之孩子 于 2006-8-22 12:38 发表
你另外一个模型就是epoll例子的模型吧
凭什么说人家的就效率低了?



我测试过。处理能力底了20%。
作者: 思一克    时间: 2006-08-22 13:11
to LZ,

你做什么服务? 有多少同时连接?
作者: wyezl    时间: 2006-08-22 13:18
原帖由 nuclearweapon 于 2006-8-22 12:02 发表
就调试来说,当服务程序挂起的时候
你可以看如下目录:
/proc/your_process_id/fd

看一看有那些fd在被你的进程使用!


我一共监视了5000个描述符,程序跑了一天,基本上快耗完了。还剩不到1000个了。


ls /proc/24152/fd/
Display all 4051 possibilities? (y or n)

可见这些耗尽的描述符都在使用中。 但不知道什么地方没把它们释放。
作者: wyezl    时间: 2006-08-22 13:22
原帖由 思一克 于 2006-8-22 13:11 发表
to LZ,

你做什么服务? 有多少同时连接?


http服务。简单的数据。基本上是读取内存的操作。类似股票行情数据。

当然每秒能处理越多请求越好。
作者: playmud    时间: 2006-08-22 13:48
5000 个?我怎么看你的listen才32?
    if (listen(fd, 32) != 0)
    {
          fprintf(stderr, "listen failed\n");
          return -1;
    }

  1. SYNOPSIS
  2.        #include <sys/socket.h>

  3.        int listen(int sockfd, int backlog);

  4. DESCRIPTION
  5.        To  accept connections, a socket is first created with socket(2), a willingness to accept incoming connec-
  6.        tions and a queue limit for incoming connections are specified with listen(), and then the connections are
  7.        accepted with accept(2).  The listen() call applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET.

  8.        The backlog parameter defines the maximum length the queue of pending connections may grow to.  If a  con-
  9.        nection request arrives with the queue full the client may receive an error with an indication of ECONNRE-
  10.        FUSED or, if the underlying protocol supports retransmission, the request may be ignored so  that  retries
  11.        succeed.
复制代码

作者: 思一克    时间: 2006-08-22 14:07
你的程序我看了。好象是有漏洞,而且是必须在大量连接,慢速的断线才可疑的。

一个fd有事件EPOLLIN后,如果断线,EPOLLOUT永不再来,你的fd不就永远不被关闭了吗?

请讨论。
作者: slay78    时间: 2006-08-22 14:13
原帖由 playmud 于 2006-8-22 13:48 发表
5000 个?我怎么看你的listen才32?
    if (listen(fd, 32) != 0)
    {
          fprintf(stderr, "listen failed\n");
          return -1;
    }

[code]SYNOPSIS
       #include <s ...


人家这个32不是表示可以连32个的意思,这个32表示最多有32个同时在连并且都没连上,第33个进不来而已
作者: 思一克    时间: 2006-08-22 14:14
虽然有HUP等else 控制。但如果EPOLLIN之后由于网络的不好状况,其它时间不在来?如何
作者: wyezl    时间: 2006-08-22 14:32
原帖由 playmud 于 2006-8-22 13:48 发表
5000 个?我怎么看你的listen才32?
    if (listen(fd, 32) != 0)
    {
          fprintf(stderr, "listen failed\n");
          return -1;
    }

[code]SYNOPSIS
       #include <s ...



这个32与5000个同时在线并不矛盾。

又不是说1秒内把这5000个连线全接受进来。
5000是我的epoll所监视的最大描述符个数。
作者: nuclearweapon    时间: 2006-08-22 14:33
原帖由 思一克 于 2006-8-22 14:14 发表
一个fd有事件EPOLLIN后,如果断线,EPOLLOUT永不再来,你的fd不就永远不被关闭了吗?


由于有SO_KEEPALIVE可以避免这种情况吧(lz的程序也做了处理)。
否则就是client有问题,一直连着不放。
作者: nuclearweapon    时间: 2006-08-22 14:34
原帖由 wyezl 于 2006-8-22 13:18 发表


我一共监视了5000个描述符,程序跑了一天,基本上快耗完了。还剩不到1000个了。


ls /proc/24152/fd/
Display all 4051 possibilities? (y or n)

可见这些耗尽的描述符都在使用中。 但不知道什么地方 ...


用ls -l 看下是那些socket
再用 netstat -a看下这些socket的状态
作者: wyezl    时间: 2006-08-22 14:38
原帖由 思一克 于 2006-8-22 14:07 发表
你的程序我看了。好象是有漏洞,而且是必须在大量连接,慢速的断线才可疑的。



就是漫漫耗尽的。

第二种模型也一样。出现这样耗尽的情况。 以前都是用测试工具测试的,基本上看不出破绽。
在线上测试,就很明显了。。
作者: 思一克    时间: 2006-08-22 14:41
to wyezl,

FD泄露,原因就是没有close是无疑问的。
WHY MEIYOU close?
就是事件有的时候(比如网络坏等原因)没有到来。
作者: wyezl    时间: 2006-08-22 14:51
原帖由 nuclearweapon 于 2006-8-22 14:34 发表


用ls -l 看下是那些socket
再用 netstat -a看下这些socket的状态



这是只监视1024个fds的时候的部分贴图。

# netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address             State      
tcp        0      0 *:32768                     *:*                         LISTEN      
tcp        0      0 *:sunrpc                    *:*                         LISTEN      
tcp        0      0 *:http                      *:*                         LISTEN      
tcp        0      0 xxx.108.37.77:http          122.48.0.37:56652           SYN_RECV   
tcp        0      0 xxx.108.37.77:http          211.147.253.74:55689        SYN_RECV   
tcp        0      0 xxx.108.37.77:http          219.135.251.110:2669        SYN_RECV   
warning, got duplicate tcp line.
tcp        0      0 xxx.108.37.77:http          122.48.0.89:12881           SYN_RECV   
tcp        0      0 xxx.108.37.77:http          58.246.194.192:4254         SYN_RECV   
tcp        0      0 xxx.108.37.77:http          122.48.0.89:12923           SYN_RECV   
tcp        0      0 xxx.108.37.77:http          218.22.98.170:56851         SYN_RECV   
tcp        0      0 xxx.108.37.77:http          122.48.0.89:12888           SYN_RECV   
tcp        0      0 xxx.108.37.77:http          60.190.192.46:4072          SYN_RECV   
tcp        0      0 xxx.108.37.77:http          61.177.227.182:27180        SYN_RECV   
tcp        0      0 xxx.108.37.77:http          60.0.218.7:41237            SYN_RECV   
tcp        0      0 xxx.108.37.77:http          221.232.42.194:3713         SYN_RECV   
tcp        0      0 xxx.108.37.77:http          218.81.111.25:4495          SYN_RECV   
tcp        0      0 xxx.108.37.77:http          122.48.0.35:59812           SYN_RECV   
tcp        0      0 xxx.108.37.77:http          58.60.5.33:7660             SYN_RECV   
tcp        0      0 xxx.108.37.77:http          222.137.4.7:4296            SYN_RECV


ls -l /proc/27952/fd/
rwx------  1 root root 64 Aug 22 14:44 837 -> socket:[31398309]
lrwx------  1 root root 64 Aug 22 14:44 838 -> socket:[31397749]
lrwx------  1 root root 64 Aug 22 14:44 839 -> socket:[31394222]
lrwx------  1 root root 64 Aug 22 14:38 84 -> socket:[30926430]
lrwx------  1 root root 64 Aug 22 14:44 840 -> socket:[31398135]
lrwx------  1 root root 64 Aug 22 14:44 841 -> socket:[31398930]
lrwx------  1 root root 64 Aug 22 14:44 842 -> socket:[31397984]
lrwx------  1 root root 64 Aug 22 14:44 843 -> socket:[31390139]
lrwx------  1 root root 64 Aug 22 14:44 844 -> socket:[31398331]
lrwx------  1 root root 64 Aug 22 14:44 845 -> socket:[31397572]
lrwx------  1 root root 64 Aug 22 14:44 846 -> socket:[31397546]
lrwx------  1 root root 64 Aug 22 14:44 847 -> socket:[31396094]
lrwx------  1 root root 64 Aug 22 14:44 848 -> socket:[31393666]
lrwx------  1 root root 64 Aug 22 14:44 849 -> socket:[31398932]
lrwx------  1 root root 64 Aug 22 14:38 85 -> socket:[30884712]
lrwx------  1 root root 64 Aug 22 14:44 852 -> socket:[31397555]
lrwx------  1 root root 64 Aug 22 14:44 856 -> socket:[31390278]
lrwx------  1 root root 64 Aug 22 14:44 858 -> socket:[31392652]
lrwx------  1 root root 64 Aug 22 14:44 859 -> socket:[31392710]
lrwx------  1 root root 64 Aug 22 14:38 86 -> socket:[30883810]
lrwx------  1 root root 64 Aug 22 14:38 87 -> socket:[30913192]
lrwx------  1 root root 64 Aug 22 14:38 88 -> socket:[30943036]
lrwx------  1 root root 64 Aug 22 14:38 89 -> socket:[31133080]
lrwx------  1 root root 64 Aug 22 14:38 9 -> socket:[30951877]
lrwx------  1 root root 64 Aug 22 14:38 90 -> socket:[30999630]
lrwx------  1 root root 64 Aug 22 14:38 91 -> socket:[31134432]
lrwx------  1 root root 64 Aug 22 14:38 92 -> socket:[30928870]
lrwx------  1 root root 64 Aug 22 14:38 93 -> socket:[30975324]
lrwx------  1 root root 64 Aug 22 14:38 94 -> socket:[30936083]
作者: wyezl    时间: 2006-08-22 14:52
原帖由 思一克 于 2006-8-22 14:41 发表
to wyezl,

FD泄露,原因就是没有close是无疑问的。
WHY MEIYOU close?
就是事件有的时候(比如网络坏等原因)没有到来。


这种情况怎么处理才好呢?
作者: 思一克    时间: 2006-08-22 14:55
你可以设置一个timeout, 超过的cfd(在ACCPTE处)一律关闭
作者: wyezl    时间: 2006-08-22 14:56
原帖由 nuclearweapon 于 2006-8-22 14:33 发表


由于有SO_KEEPALIVE可以避免这种情况吧(lz的程序也做了处理)。
否则就是client有问题,一直连着不放。


我没有支持KEEPALIVE。发送完处理,立刻就关闭描述符了。
作者: wyezl    时间: 2006-08-22 15:01
原帖由 思一克 于 2006-8-22 14:55 发表
你可以设置一个timeout, 超过的cfd(在ACCPTE处)一律关闭

怎么为每个描述符设置超时?
作者: nuclearweapon    时间: 2006-08-22 15:01
原帖由 wyezl 于 2006-8-22 14:51 发表



这是只监视1024个fds的时候的部分贴图。

# netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address             State ...



难道有人攻击你

SYN_RECV有多少个!
作者: nuclearweapon    时间: 2006-08-22 15:04
你打开tcp_syncookies
试试。
再做测试
作者: 思一克    时间: 2006-08-22 15:07
可能不是好方法:

while( ......... accept()  ....) {


  ....这里检查全局的time_t fd_create[5000];

}

关闭时设置fd_create[fd] = 0;
作者: wyezl    时间: 2006-08-22 15:11
原帖由 nuclearweapon 于 2006-8-22 15:01 发表



难道有人攻击你

SYN_RECV有多少个!


几百个吧。贴出来。省略一部分后面的。
# netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address             State      
tcp        0      0 *:32768                     *:*                         LISTEN      
tcp        0      0 *:sunrpc                    *:*                         LISTEN      
tcp        0      0 *:http                      *:*                         LISTEN      
tcp        0      0 xxx.108.37.77:http          58.217.195.47:4689          SYN_RECV   
tcp        0      0 xxx.108.37.77:http          58.47.42.74:2899            SYN_RECV   
tcp        0      0 xxx.108.37.77:http          218.68.242.127:1238         SYN_RECV   
tcp        0      0 xxx.108.37.77:http          222.67.10.49:30384          SYN_RECV   
tcp        0      0 xxx.108.37.77:http          pc68.broad.dynamic.xm.:2215 SYN_RECV   
tcp        0      0 xxx.108.37.77:http          220.191.231.198:47700       SYN_RECV   
tcp        0      0 xxx.108.37.77:http          218.77.186.194:63425        SYN_RECV   
tcp        0      0 xxx.108.37.77:http          220.207.230.113:3652        SYN_RECV   
tcp        0      0 xxx.108.37.77:http          60.7.59.197:3216            SYN_RECV   
tcp        0      0 xxx.108.37.77:http          123.49.160.226:3127         SYN_RECV   
warning, got duplicate tcp line.
tcp        0      0 xxx.108.37.77:http          122.48.0.89:13698           SYN_RECV   
tcp        0      0 xxx.108.37.77:http          58.67.158.106:krb524        SYN_RECV   
tcp        0      0 xxx.108.37.77:http          218.79.187.16:3129          SYN_RECV   
tcp        0      0 xxx.108.37.77:http          122.48.0.89:13680           SYN_RECV   
tcp        0      0 xxx.108.37.77:http          60.171.192.39:2531          SYN_RECV   
tcp        0      0 xxx.108.37.77:http          60.216.170.48xx5          SYN_RECV   
warning, got duplicate tcp line.
tcp        0      0 xxx.108.37.77:http          218.22.68.194:1101          SYN_RECV   
tcp        0      0 xxx.108.37.77:http          219.137.172.101:15053       SYN_RECV   
tcp        0      0 xxx.108.37.77:http          61.141.94.21:4748           SYN_RECV   
tcp        0      0 xxx.108.37.77:http          58.24.101.69:4188           SYN_RECV   
tcp        0      0 xxx.108.37.77:http          222.82.225.134:3118         SYN_RECV   
tcp        0      0 xxx.108.37.77:http          59.52.119.145:55806         SYN_RECV   
tcp        0      0 xxx.108.37.77:http          124.248.1.69:50344          SYN_RECV   
tcp        0      0 xxx.108.37.77:http          220.171.79.196:3014         SYN_RECV   
tcp        0      0 xxx.108.37.77:http          123.49.164.148:55258        SYN_RECV   
tcp        0      0 xxx.108.37.77:http          212.193.163.60.broad.:63429 SYN_RECV   
tcp        0      0 xxx.108.37.77:http          122.48.0.89:13754           SYN_RECV   
tcp        0      0 xxx.108.37.77:http          61.188.210.2:3532           SYN_RECV   
tcp        0      0 xxx.108.37.77:http          122.48.0.89:13752           SYN_RECV   


[root@sina src]# netstat -an | more
warning, got duplicate tcp line.
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address             State      
tcp        0      0 0.0.0.0:32768               0.0.0.0:*                   LISTEN      
tcp        0      0 0.0.0.0:111                 0.0.0.0:*                   LISTEN      
tcp        0      0 0.0.0.0:80                  0.0.0.0:*                   LISTEN      
tcp        0      0 xxx.108.37.77:80            xxx.103.215.242:62165       SYN_RECV   
tcp        0      0 xxx.108.37.77:80            220.191.231.198:47700       SYN_RECV   
tcp        0      0 xxx.108.37.77:80            218.246.73.21:60164         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            222.64.136.219:2881         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            123.49.160.226:3127         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            60.63.11.185:22834          SYN_RECV   
tcp        0      0 xxx.108.37.77:80            58.51.39.146:1870           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            122.48.0.89:13698           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            211.147.240.74:3076         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            59.54.226.64:1135           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            218.28.166.198:61757        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            222.82.225.134:3118         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            58.35.242.69:23660          SYN_RECV   
tcp        0      0 xxx.108.37.77:80            211.92.156.131:1210         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            221.5.82.81:2100            SYN_RECV   
tcp        0      0 xxx.108.37.77:80            220.171.79.196:3014         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            60.163.193.212:63429        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            122.48.0.89:13754           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            61.188.210.2:3532           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            218.82.23.151:64811         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            122.48.0.89:13752           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            218.18.33.108:4641          SYN_RECV   
tcp        0      0 xxx.108.37.77:80            211.95.165.175:61439        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            218.28.188.86:52324         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            211.92.156.131:1215         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            211.92.156.131:1206         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            218.71.200.192:1503         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            221.200.137.120:1619        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            218.59.106.182:53008        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            211.69.18.125:3158          SYN_RECV   
tcp        0      0 xxx.108.37.77:80            218.81.193.198:1434         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            61.144.254.129:50050        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            211.92.156.131:1216         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            218.28.58.69:9898           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            220.234.241.178:1679        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            219.242.196.109:2261        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            124.21.243.228:1648         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            221.200.137.120:1620        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            222.35.126.211:1336         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            221.234.146.160:2188        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            222.169.187.100:3529        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            122.48.0.89:13748           SYN_RECV   
--More--warning, got duplicate tcp line.
warning, got duplicate tcp line.
warning, got duplicate tcp line.
tcp        0      0 xxx.108.37.77:80            218.246.73.21:60165         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            221.196.131.130:4444        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            220.174.8.13:12043          SYN_RECV   
tcp        0      0 xxx.108.37.77:80            211.95.165.175:61440        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            220.205.30.17:1519          SYN_RECV   
tcp        0      0 xxx.108.37.77:80            61.188.210.2:3531           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            60.163.193.212:63427        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            218.94.127.135:30598        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            219.155.143.97:1120         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            221.7.131.131:4331          SYN_RECV   
tcp        0      0 xxx.108.37.77:80            211.147.240.74:3077         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            210.76.66.35:1524           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            61.138.254.47:29233         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            59.35.87.21:11079           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            219.242.196.109:2260        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            220.205.30.17:1518          SYN_RECV   
tcp        0      0 xxx.108.37.77:80            58.62.84.52:4315            SYN_RECV   
tcp        0      0 xxx.108.37.77:80            221.216.74.228:4444         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            222.169.187.100:3528        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            211.92.156.131:1207         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            222.209.217.21:38807        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            219.238.191.17:17679        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            61.172.137.186:4075         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            211.92.156.131:1212         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            221.214.13.109:17600        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            218.23.149.98:46060         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            221.222.116.178:1658        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            xxx.103.215.242:62164       SYN_RECV   
tcp        0      0 xxx.108.37.77:80            222.173.191.91:1143         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            61.242.112.118:59158        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            222.209.217.21:38551        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            219.129.164.182:62607       SYN_RECV   
tcp        0      0 xxx.108.37.77:80            58.60.67.4:48095            SYN_RECV   
tcp        0      0 xxx.108.37.77:80            211.92.156.131:1213         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            122.48.0.89:13694           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            218.87.71.62:2363           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            61.173.14.106:4444          SYN_RECV   
tcp        0      0 xxx.108.37.77:80            220.234.241.178:1678        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            210.21.209.145:5554         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            122.48.0.89:13750           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            59.35.87.21:11080           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            61.172.137.186:4076         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            222.67.94.46:1434           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            122.48.0.89:13697           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            61.242.112.118:59160        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            58.35.242.69:23659          SYN_RECV   
--More--warning, got duplicate tcp line.
warning, got duplicate tcp line.
tcp        0      0 xxx.108.37.77:80            61.181.71.50:3946           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            211.92.156.131:1209         SYN_RECV   
tcp        0      0 xxx.108.37.77:80            60.63.11.185:22833          SYN_RECV   
tcp        0      0 xxx.108.37.77:80            122.48.0.89:13744           SYN_RECV   
tcp        0      0 xxx.108.37.77:80            222.137.152.197:4755        SYN_RECV   
tcp        0      0 xxx.108.37.77:80            220.169.5.239:3676          SYN_RECV   
tcp        0      0 127.0.0.1:631               0.0.0.0:*                   LISTEN      
tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      
tcp        0      0 xxx.108.37.77:80            221.6.163.131:35293         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.198.127.25:1956         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            60.2.106.52:58968           TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.222.144.24:1618         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            211.158.132.14:1808         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            218.89.188.200:60118        TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.0.180.142:58305         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            61.51.223.223:1992          TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            61.170.213.11:14704         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            219.136.26.220:3765         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            211.158.81.195:4087         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            218.71.200.192:1460         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.5.152.50:37803          TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            210.21.232.236:33515        TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.198.127.25:1957         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.15.17.77:1878           TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.1.244.62:1230           TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            61.155.209.139:2875         TIME_WAIT   
tcp        1      1 xxx.108.37.77:80            60.186.14.190:13808         CLOSING     
tcp        0      0 xxx.108.37.77:80            60.208.111.253:57016        TIME_WAIT   
tcp        1      1 xxx.108.37.77:80            219.145.113.15:52970        CLOSING     
tcp        0      0 xxx.108.37.77:80            61.170.213.11:14705         TIME_WAIT   
tcp        1      1 xxx.108.37.77:80            xxx.106.180.254:2266        CLOSING     
tcp        1      1 xxx.108.37.77:80            222.68.248.150:7632         CLOSING     
tcp        0      0 xxx.108.37.77:80            60.17.17.149:62063          TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            60.0.16.66:3159             TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            58.101.33.97:3616           TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            125.32.0.114:1367           TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            125.33.217.83:3502          TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            71.135.63.37:61595          TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            218.26.227.9:31478          TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            220.161.163.113:1141        TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.1.244.62:1229           TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            60.2.106.52:58970           TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.15.17.77:1877           TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            222.64.14.150:64545         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            222.67.166.24:2299          TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            61.51.223.223:1994          TIME_WAIT   
--More--warning, got duplicate tcp line.
warning, got duplicate tcp line.
tcp        0      0 xxx.108.37.77:80            61.155.18.18:56733          TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            60.15.21.5:12313            TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            58.33.225.117:2739          TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            61.167.60.224:58498         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            58.60.5.33:7454             TIME_WAIT   
tcp        0    243 xxx.108.37.77:80            218.71.200.192:1718         FIN_WAIT1   
tcp        0      0 xxx.108.37.77:80            123.49.164.148:55288        TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            125.33.217.83:3501          TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.214.13.109:47024        TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.218.117.87:17919        TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            218.108.44.10:21325         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            124.200.18.190:3484         TIME_WAIT   
tcp        0    300 xxx.108.37.77:80            221.218.117.87:26879        FIN_WAIT1   
tcp        0    567 xxx.108.37.77:80            221.218.117.87:27135        FIN_WAIT1   
tcp        0      0 xxx.108.37.77:80            218.26.227.9:31479          TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            220.161.163.113:1140        TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.222.144.24:1617         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            60.2.106.52:58971           TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.5.181.31:3752           TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            61.49.166.124:62700         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.0.180.142:58306         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            61.51.223.223:1995          TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            60.208.111.253:57018        TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            xxx.111.152.6:56054         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            58.33.225.117:2738          TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            61.181.245.85:25618         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            123.49.164.148:55289        TIME_WAIT   
tcp        1      1 xxx.108.37.77:80            125.92.214.174:6619         CLOSING     
tcp        0      0 xxx.108.37.77:80            124.200.18.190:3483         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            60.166.100.106:48296        TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            222.223.6.176:40086         ESTABLISHED
tcp        0      0 xxx.108.37.77:80            124.42.126.70:55826         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.226.242.212:64827       TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.198.127.25:1952         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            222.64.14.150:64295         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            xxx.106.113.61:6182         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.229.12.88:4273          TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            61.49.166.124:62699         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            221.8.9.91:5210             TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            210.21.196.86:11655         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            218.87.255.183:3552         TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            61.181.250.190:32782        TIME_WAIT   
tcp        0      0 xxx.108.37.77:80            125.33.217.83:3499          TIME_WAIT
作者: wyezl    时间: 2006-08-22 15:12
原帖由 nuclearweapon 于 2006-8-22 15:04 发表
你打开tcp_syncookies
试试。
再做测试

怎么打开?
作者: 思一克    时间: 2006-08-22 15:14
wyezl,

攻击不会影响FD。FD是已经建立的连接没close.
作者: 思一克    时间: 2006-08-22 15:15
这个帖子可以做为精华了。因为问题微妙又棘手,有普遍性,尤其对与EPOLL
作者: nuclearweapon    时间: 2006-08-22 15:17
标题: 回复 59楼 wyezl 的帖子
如果一直有大量的SYN_RECV就有可能是攻击。

echo 1 > /proc/sys/net/ipv4/tcp_syncookies
可以打开。

下边还有几个都是对付 ddos的。太具体要自己查查。
作者: wyezl    时间: 2006-08-22 15:23
原帖由 思一克 于 2006-8-22 15:14 发表
wyezl,

攻击不会影响FD。FD是已经建立的连接没close.



我暂时的方法是描述符用完了,就退出。
由监视程序定时检查和重启。
这不知道是不是epoll自身的缺陷。
作者: nuclearweapon    时间: 2006-08-22 15:25
原帖由 思一克 于 2006-8-22 15:14 发表
wyezl,

攻击不会影响FD。FD是已经建立的连接没close.


我记得和斑竹有一些出入。
因为:
只要有socket就会有一个inode,也就会有一个fd。而不是连接以后才会有fd的。
对于linux2。6来说
每当在内核创建完struct socket后,就会调用sock_map_fd()在调用进程创建一个fd。

如果有SYN_RECV状态,也就有了struct socket,也就有了inode,进而有了fd。
希望指正!

[ 本帖最后由 nuclearweapon 于 2006-8-22 15:27 编辑 ]
作者: 思一克    时间: 2006-08-22 15:26
应该不是epoll本身的问题。epoll采样事件,如果事件没有来它也无能为力。timeout是必须的
作者: wyezl    时间: 2006-08-22 15:27
原帖由 思一克 于 2006-8-22 15:15 发表
这个帖子可以做为精华了。因为问题微妙又棘手,有普遍性,尤其对与EPOLL


如果能讨论出一个成熟的,通用的epoll模型。 加精华也不亏。呵呵。
我继续线上测试。

uname -a
Linux xxx.com.cn 2.6.9-34.EL #1 Wed Mar 8 00:07:35 CST 2006 i686 i686 i386 GNU/Linux
[finance@sina src]$ cat /etc/issue
CentOS release 4.1 (Final)
Kernel \r on an \m
作者: 思一克    时间: 2006-08-22 15:30
TO nuclearweapon,

你说的对。但他的问题是accept之后的fd被耗尽了,那就是有连接的socket.

如果那些DDOS攻击,往往是半连接(部分IP包),accept不了。


原帖由 nuclearweapon 于 2006-8-22 15:25 发表


我记得和斑竹有一些出入。
因为:
只要有socket就会有一个inode,也就会有一个fd。而不是连接以后才会有fd的。
对于linux2。6来说
每当在内核创建完struct socket后,就会调用sock_map_fd()在调用进程创建 ...

作者: nuclearweapon    时间: 2006-08-22 15:35
原帖由 思一克 于 2006-8-22 15:30 发表
TO nuclearweapon,

你说的对。但他的问题是accept之后的fd被耗尽了,那就是有连接的socket.

如果那些DDOS攻击,往往是半连接(部分IP包),accept不了。





就是这半连接的socket把fd用完了。
因为只有有了socket才可能有sycrcv状态。
作者: 思一克    时间: 2006-08-22 15:42
To nuclearweapon,

也有可能是攻击引起的。让他继续实验。
半连接accept能成功返回fd吗?我不是十分肯定。
作者: nuclearweapon    时间: 2006-08-22 15:45
标题: 回复 思一克
对于半连接来说accpet是不能返回了,但是在内核中fd已经建立起来了,也就消耗了一个进程的可用fd数量。
作者: wyezl    时间: 2006-08-22 15:50
原帖由 思一克 于 2006-8-22 15:42 发表
To nuclearweapon,

也有可能是攻击引起的。让他继续实验。
半连接accept能成功返回fd吗?我不是十分肯定。


现在访问量下降了。
SYN_RECV 也下降到了只有20~30个。

恶意攻击的可能性比较小。
是不是由于我的次序造成的?
作者: 思一克    时间: 2006-08-22 15:52
TO nuclearweapon,

你肯定没有建立的连接,没有accept的也消耗KERNEL中的fd吗? 我不SURE
作者: wyezl    时间: 2006-08-22 15:54
原帖由 nuclearweapon 于 2006-8-22 15:45 发表
对于半连接来说accpet是不能返回了,但是在内核中fd已经建立起来了,也就消耗了一个进程的可用fd数量。



我可以统计一段时间内, accpet的总数,和close的总数。看他们的差是不是等于。
/etc/pid/fd 下面的fd数。
作者: 思一克    时间: 2006-08-22 16:00
TO nuclearweapon,

我刚才看了KERNEL代码,看到fd消耗只有3个函数socket() , accept(), socketpair(), 而且都是成功后才消耗fd. 网络程序其它任何地方没有看到用fd的?

半连接能消耗fd吗,我不是很清楚。如果你清楚就写出来。

谢谢

原帖由 nuclearweapon 于 2006-8-22 15:45 发表
对于半连接来说accpet是不能返回了,但是在内核中fd已经建立起来了,也就消耗了一个进程的可用fd数量。

作者: wyezl    时间: 2006-08-22 16:05
现在访问量比较少的时候。fd随时间变化情况。当然是重新启动之后测试的。这样看起来基本没问题。
压力上来后就漫漫变了。

[root@xxx ~]# ls /proc/28305/fd/
0   10  12  14  16  18  2   21  23  25  28  4   6   8   
1   11  13  15  17  19  20  22  24  27  3   5   7   9   
[root@xxx ~]# ls /proc/28305/fd/
0   10  12  14  16  18  2   21  23  25  28  4   6   8   
1   11  13  15  17  19  20  22  24  27  3   5   7   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  12  13  14  15  16  17  18  19  2   20  21  22  24  3   4   5   6   7   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   11  12  13  14  15  16  17  18  2   20  21  24  3   4   5   6   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  12  13  14  15  16  17  18  2   20  21  24  3   4   5   6   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  12  13  14  15  16  17  18  2   20  21  24  3   4   5   6   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  12  13  14  15  16  17  18  2   24  3   4   5   6   7   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  12  13  14  15  18  2   3   4   5   6   7   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  12  13  14  15  16  18  2   3   4   5   6   7   8   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  13  14  15  16  17  18  2   3   4   5   6   7   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  12  13  14  15  16  17  18  19  2   3   4   5   6   7   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  12  13  14  15  16  17  2   3   4   5   6   7   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   11  12  13  14  15  17  19  2   3   4   5   6   7   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  12  13  14  15  17  19  2   3   4   5   6   7   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  13  14  15  17  19  2   3   4   5   6   7   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  13  14  15  16  17  19  2   3   4   5   6   7   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   11  12  13  14  15  16  17  19  2   3   4   5   6   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  13  14  15  16  17  18  19  2   20  21  3   4   5   6   7   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  13  14  15  16  17  18  19  2   20  21  3   4   5   6   7   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  12  13  14  15  16  17  18  19  2   20  21  3   4   5   6   7   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  12  13  14  15  17  18  19  2   20  21  3   4   5   6   7   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  12  13  14  15  17  18  19  2   20  21  3   4   5   6   7   8   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  12  13  14  15  18  2   20  21  3   4   5   6   7   8   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  12  13  14  15  2   21  3   4   5   6   7   8   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  12  13  14  15  2   3   4   5   6   7   8   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  12  13  14  15  2   3   4   5   6   7   8   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  12  13  14  15  2   3   4   5   6   7   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  13  14  15  2   3   4   5   6   7   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  14  15  2   3   4   5   6   7   8   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  13  14  15  2   3   4   5   6   7   8   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  14  15  2   3   4   5   6   8   
[root@xxx ~]# ls /proc/28305/fd/
0   1   10  11  12  14  15  2   3   4   5   6   7   8   9   
[root@xxx ~]# ls /proc/28305/fd/
0   1   11  14  15  2   3   4   5   6   7   8

[ 本帖最后由 wyezl 于 2006-8-22 16:09 编辑 ]
作者: 思一克    时间: 2006-08-22 16:09
TO LZ,

我的服务器也有许多攻击 SYN_RECV. 但基本不影响,更没有fd没有了的情况。
作者: wyezl    时间: 2006-08-22 16:22
是在线上测试吗?一小时能达到100万请求数的时候就能看出来了。

用测试工具好象不行。测试不错破绽。
我现在访问量也下降了,不好测了。
作者: 思一克    时间: 2006-08-22 16:26
to LZ,

我试图在我一个SERVER上跑80(有IP),遗憾的是无法编译,因为EPOLL支持问题
作者: wyezl    时间: 2006-08-22 16:32
原帖由 思一克 于 2006-8-22 16:26 发表
to LZ,

我试图在我一个SERVER上跑80(有IP),遗憾的是无法编译,因为EPOLL支持问题


谢谢热心的斑竹,耽误了你不少时间。
这个没有环境不好测。
我再自己想想办法。
不知道有没有什么可以跟踪一个描述符使用的。

刚才模拟100万个请求,只丢了一个描述符。 模拟很难发现问题。
肯定是跟网络状态有关。

[ 本帖最后由 wyezl 于 2006-8-22 16:40 编辑 ]
作者: 思一克    时间: 2006-08-22 16:45
不用谢。仅仅是我觉得你这个程序的完善有意义。我也从中学习了。
作者: nuclearweapon    时间: 2006-08-22 16:50
原帖由 思一克 于 2006-8-22 16:00 发表
TO nuclearweapon,

我刚才看了KERNEL代码,看到fd消耗只有3个函数socket() , accept(), socketpair(), 而且都是成功后才消耗fd. 网络程序其它任何地方没有看到用fd的?

半连接能消耗fd吗,我不是很清楚。如 ...


按照我的理解,netstat都看到了socket的状态所以就应当有 struct socket了。



可能是我错了。
我也在看代码。查找原因

多谢指教!
作者: tysn    时间: 2006-08-22 16:55
可不可以不用分成
if(events[ i].events & EPOLLIN)

else if(events[ i].events & EPOLLOUT)
两种情况?

只要有事件来就进行读写,
当然要对读写cfd的函数进行出错判断,一旦出错就close(cfd)
这样就能避免EPOLLN之后EPOLLOUT永不再来的情况?
原帖由 思一克 于 2006-8-22 14:07 发表
你的程序我看了。好象是有漏洞,而且是必须在大量连接,慢速的断线才可疑的。

一个fd有事件EPOLLIN后,如果断线,EPOLLOUT永不再来,你的fd不就永远不被关闭了吗?

请讨论。

前提是假定产生EPOLLN事件(可读)的socket一定也可写

[ 本帖最后由 tysn 于 2006-8-22 16:59 编辑 ]
作者: 思一克    时间: 2006-08-22 16:56
TO nuclearweapon,

我也不是多肯定,所以谈不到指教。你太客气。

fd好象是最后需要(仅仅是一个下标),而且都是本地(本问题中是SERVER)的APP的直接调用SOCK函数才可以产生。CLIENT要想在本机上产生fd, accept要成功
作者: wyezl    时间: 2006-08-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 root 64 Aug 22 16:14 0 -> /dev/pts/3
lrwx------  1 root root 64 Aug 22 16:14 1 -> /dev/pts/3
lrwx------  1 root root 64 Aug 22 16:14 10 -> socket:[34584054]
lrwx------  1 root root 64 Aug 22 16:14 11 -> socket:[34584140]
lrwx------  1 root root 64 Aug 22 16:14 12 -> socket:[32509524]
lrwx------  1 root root 64 Aug 22 16:14 13 -> /usr/home/fi/src/home/ww
lrwx------  1 root root 64 Aug 22 16:14 14 -> socket:[34584144]
lrwx------  1 root root 64 Aug 22 16:14 15 -> socket:[34584145]
lrwx------  1 root root 64 Aug 22 16:14 16 -> socket:[34584147]
lrwx------  1 root root 64 Aug 22 16:14 17 -> socket:[34584152]
lrwx------  1 root root 64 Aug 22 16:14 2 -> /dev/pts/3
lrwx------  1 root root 64 Aug 22 16:16 23 -> socket:[34543624]
lr-x------  1 root root 64 Aug 22 16:14 3 -> eventpoll:[32224366]
lrwx------  1 root root 64 Aug 22 16:14 4 -> socket:[32224367]
lrwx------  1 root root 64 Aug 22 16:25 480 -> socket:[34370805]
lr-x------  1 root root 64 Aug 22 16:14 5 -> /usr/home/fi/src/home/ww
lrwx------  1 root root 64 Aug 22 16:36 6 -> socket:[34581817]
lrwx------  1 root root 64 Aug 22 16:14 7 -> socket:[33195785]
lrwx------  1 root root 64 Aug 22 16:36 8 -> socket:[34584130]
lrwx------  1 root root 64 Aug 22 16:14 9 -> socket:[34583662]
作者: wyezl    时间: 2006-08-22 17:10
原帖由 tysn 于 2006-8-22 16:55 发表
可不可以不用分成
if(events[ i].events & EPOLLIN)

else if(events[ i].events & EPOLLOUT)
两种情况?

只要有事件来就进行读写,
当然要对读写cfd的函数进行出错判断,一旦出错就close(cfd) ...


这个效率有点低。
因为可能会产生等待可写。
作者: playmud    时间: 2006-08-22 17:35
原帖由 wyezl 于 2006-8-22 14:32 发表



这个32与5000个同时在线并不矛盾。

又不是说1秒内把这5000个连线全接受进来。
5000是我的epoll所监视的最大描述符个数。

怎么不矛盾了?
你是if ((fd = socket(AF_INET, SOCK_STREAM, 0)) <= 0)
你把listen设成5000看看。
作者: wyezl    时间: 2006-08-22 17:43
原帖由 playmud 于 2006-8-22 17:35 发表

怎么不矛盾了?
你是if ((fd = socket(AF_INET, SOCK_STREAM, 0)) <= 0)
你把listen设成5000看看。


5000以内的描述符我都能 接受到。

设那个没什么影响。 估计listen也不能支持那么大的。
作者: playmud    时间: 2006-08-22 17:49
tcp正常的断开需要3次或者4次握手确认,如果没有这个确认他就会保持一定的时间。
/proc/sys/net/ipv4/tcp_keepalive_time
作者: playmud    时间: 2006-08-22 17:50
原帖由 wyezl 于 2006-8-22 17:43 发表


5000以内的描述符我都能 接受到。

设那个没什么影响。 估计listen也不能支持那么大的。

你能接收到和你能处理掉不是一个概念。
作者: playmud    时间: 2006-08-22 17:52
实在找不到原因,你可以把那个默认超时时间设成10几秒或者几十秒。
系统帮你释放掉占用的资源。
作者: wyezl    时间: 2006-08-22 17:53
原帖由 playmud 于 2006-8-22 17:49 发表
tcp正常的断开需要3次或者4次握手确认,如果没有这个确认他就会保持一定的时间。
/proc/sys/net/ipv4/tcp_keepalive_time


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

有的死掉的描述符再给它一个小时它也不会释放了,肯定是没close。
作者: wyezl    时间: 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



复制代码

作者: wyezl    时间: 2006-08-22 18:25
原帖由 playmud 于 2006-8-22 17:52 发表
实在找不到原因,你可以把那个默认超时时间设成10几秒或者几十秒。
系统帮你释放掉占用的资源。

哪个默认的超时?
作者: nuclearweapon    时间: 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_
如果照你说只有一个的话就很好分析出是拿一个是那个死掉的。看看他的状态是什么
作者: safedead    时间: 2006-08-22 23:15
我写的一个非常简单的epoll服务器,
监听从8000到12999共计5000个端口
预创建4096个线程
主线程用线程锁调度

具体代码见: http://www.cublog.cn/u/17999/showart.php?id=159057
作者: wyezl    时间: 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是谁的?
怎么看状态?
作者: nuclearweapon    时间: 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
作者: wyezl    时间: 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.
作者: 思一克    时间: 2006-08-23 14:42
原因看来就是我原来想的那样。
作者: wyezl    时间: 2006-08-23 15:24
这样做效率低了一些。暂时也没好的办法。
如果用线程池效率也是会有影响。

猜测是,一些fd加入了epoll的监视中,但确没有任何事件触发。
所以就都死到里面了。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2