免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 13996 | 回复: 13

[C] [求助]accept出错为EMFILE时为什么要调用listen(sfd,0)? [复制链接]

论坛徽章:
0
发表于 2009-07-01 18:46 |显示全部楼层
我看到memcached里面有一段代码,其中当accept错误代码为EMFILE时会调用 accept_new_conns,而accept_new_conns将调用listen(sfd,0),为什么要这样调用呢?

            if ((sfd = accept(c->sfd, (struct sockaddr *)&addr, &addrlen)) == -1) {
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
                    /* these are transient, so don't log anything */
                    stop = true;
                } else if (errno == EMFILE) {
                    accept_new_conns();
                    stop = true;
                } else {
                    perror("accept()");
                    stop = true;
                }
                break;
            }

其中:accept_new_conns代码简写如下:

void do_accept_new_conns(void) {

            update_event(next, 0);
            if (listen(next->sfd, 0) != 0) {
                perror("listen");
            }
  
}

[ 本帖最后由 wwdwwd 于 2009-7-1 22:09 编辑 ]

论坛徽章:
0
发表于 2009-07-01 19:38 |显示全部楼层
顶一下,请大家帮忙看一下,thanks

论坛徽章:
5
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:53:172015亚冠之水原三星
日期:2015-06-02 16:34:202015年亚冠纪念徽章
日期:2015-10-19 18:13:37程序设计版块每日发帖之星
日期:2015-11-08 06:20:00
发表于 2009-07-01 21:27 |显示全部楼层
listen()第二个参数为0,行为怎么定义的. 你从哪里看到的是 "不再监听socket了"

论坛徽章:
0
发表于 2009-07-01 22:08 |显示全部楼层
原帖由 xinglp 于 2009-7-1 21:27 发表
listen()第二个参数为0,行为怎么定义的. 你从哪里看到的是 "不再监听socket了"

嗯,谢谢哥们,确实不是这个意思。我仔细的看了一下unp对于listen(int fd,int listenq)的解释,
对listenq正确的解释应该是内核为监听套接口排队的最大个数,但这个个数不一定是未连接队列或已连接队列的个数,具体操作系统不一样,内核实际能排队的个数并不一定就是listenq,但跟listenq有一定关系,里面还提到不能将listenq设置为0,因为有的系统在设置为0后就不排队了,也就是相当于不提供server服务了。
     但是这里我不明白的是:为什么memcached要在accept的错误为EMFILE时要修改listen(sfd,0),而且还把libevent里面的监听事件设置为0?我觉得它不再监听libevent的事件可以理解,因为accept调用返回EMFILE的意思是打开的文件过多,既然此时文件描述符已经很多了,而一旦监听libevent就意味着要accept,一旦accept就意味着要增加文件描述符(因为accept要返回一个新的文件描述符),但是为什么要重新调用
listen(sfd,0)呢,想不明白

[ 本帖最后由 wwdwwd 于 2009-7-2 09:53 编辑 ]

论坛徽章:
5
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:53:172015亚冠之水原三星
日期:2015-06-02 16:34:202015年亚冠纪念徽章
日期:2015-10-19 18:13:37程序设计版块每日发帖之星
日期:2015-11-08 06:20:00
发表于 2009-07-02 00:07 |显示全部楼层
listen()有个队列(或者说内核里面有个队列), 就算服务端没有accept(),客户端也能connect()成功甚至能够发送数据.

一旦程序不能成功accept()队列中已有的连接(比如发生EMFILE),队列会很快变满(进行并发压力测试或者负载很高的情况下), 队列变满之后,监听套接字上便不会再次触发边沿事件, 也就是epoll的ET模式下的事件.   这种情况下即便程序关闭了一些套接字(比如由超时处理关闭)并能够再次进行accept(),  但是程序不会被通知进行accept(), 也就不能继续提供服务了.   所以这种情况要做一下处理.  我通常的做法是发生EMFILE之后定期的epoll_ctl(...MOD...)一下监听套接字以便再次触发.

个人意见,仅供参考

[ 本帖最后由 xinglp 于 2009-7-2 00:09 编辑 ]

论坛徽章:
0
发表于 2009-07-02 09:41 |显示全部楼层
原帖由 xinglp 于 2009-7-2 00:07 发表
listen()有个队列(或者说内核里面有个队列), 就算服务端没有accept(),客户端也能connect()成功甚至能够发送数据.

一旦程序不能成功accept()队列中已有的连接(比如发生EMFILE),队列会很快变满(进行并发压力测 ...



分析得很有道理。。。

论坛徽章:
0
发表于 2009-07-02 11:32 |显示全部楼层
原帖由 xinglp 于 2009-7-2 00:07 发表
listen()有个队列(或者说内核里面有个队列), 就算服务端没有accept(),客户端也能connect()成功甚至能够发送数据.

一旦程序不能成功accept()队列中已有的连接(比如发生EMFILE),队列会很快变满(进行并发压力测 ...

非常感谢你的回复,但有几个问题:
1:对于epoll来说,监听套接字是不应该使用ET模式的,因为在ET模式下,如果同时有多个连接过来,epoll只会通知一次,也就是会认为只有一个连接,这是不好的,因此不能这么做;
2:即便让监听套接字使用ET模式,也不会出现accept()返回EMFILE错误,因为既然TCP的已连接队列满了之后epoll不会再通知应用程序了,那么应用程序也就不会再调用accept()了,因为应用程序的逻辑应该是:监听套接字得到epoll通知后才去accept的,对吧?
   我测试的结果也是这样的,监听套接字上使用ET模式下不会出现EMFILE错误;
3:你说的‘ 发生EMFILE之后定期的epoll_ctl(...MOD...)一下监听套接字以便再次触发.’指的是什么意思?
是说本来已经无法得到监听套接字的可读事件了,重新epoll_ctl(...MOD...)一下就又可以得到监听套接字的可读事件了,epoll可以这么做,对吗?就是说对于一个事件,epoll本来检测不到了,重新epoll_ctl(...MOD...)一下就又可以检测到啦

请指教,thanks

论坛徽章:
0
发表于 2009-07-02 11:38 |显示全部楼层
为了方便,贴一下测试代码,其中epoll.c是服务端代码,thread.c是客户端代码,客户端代码的使用方式是:./thread 10000(线程数)

[ 本帖最后由 wwdwwd 于 2009-7-2 11:40 编辑 ]

桌面.rar

2.74 KB, 下载次数: 95

论坛徽章:
5
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:53:172015亚冠之水原三星
日期:2015-06-02 16:34:202015年亚冠纪念徽章
日期:2015-10-19 18:13:37程序设计版块每日发帖之星
日期:2015-11-08 06:20:00
发表于 2009-07-02 15:34 |显示全部楼层
原帖由 wwdwwd 于 2009-7-2 11:32 发表

非常感谢你的回复,但有几个问题:
1:对于epoll来说,监听套接字是不应该使用ET模式的,因为在ET模式下,如果同时有多个连接过来,epoll只会通知一次,也就是会认为只有一个连接,这是不好的,因此不能这么 ...


1.监听套接字使用ET模式的时候需要循环accept()直到EAGAIN为止.
2.EMFILE和epoll没有直接关系.
3.我这里可以再次通知.

论坛徽章:
0
发表于 2009-07-02 17:09 |显示全部楼层
原帖由 xinglp 于 2009-7-2 15:34 发表


1.监听套接字使用ET模式的时候需要循环accept()直到EAGAIN为止.
2.EMFILE和epoll没有直接关系.
3.我这里可以再次通知.

你说的很对,是需要循环accept直到EAGAIN,我之前想的不全面。
我再改一下程序试试看,看看能否得到通知,thanks very much
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP