TCP_DEFER_ACCEPT的坑

我实现了一个server,支持HTTP协议和内部私有协议,为了简化部署,我设计成一个端口同时兼容两种协议的客户端。根据连接后到达的消息头自动识别客户端协议。这种事情的传统做法是,accept后加入epoll,当fd第一次可读时,读出一些并解析,判断协议类型。

创建相应的上下文对象,开始服务。这样就引入了中间状态,为了省事,我用了TCP_DEFER_ACCEPT来简化这个过程。

TCP_DEFER_ACCEPT,是Linux下的socket支持一个tcp选项,man这么说的:

TCP_DEFER_ACCEPT

    Allows a listener to be awakened only when data arrives on the socket. Takes an integer value (seconds), this can bound the maximum number of
  attempts TCP will make to complete the connection. This option should not be used in code intended to be portable.

这样,当accept后,马上就读出并解析协议头,然后再把fd设置为非阻塞的,创建上下文对象,代码简化了不少。

但是今天用大量短连接压测时,发现连接数过了几千后,程序急剧变慢,最后干脆停止响应了。gdb上去看发现居然阻塞在recv的地方,加时间日志发现,recv居然有不少耗时数百毫秒,而如果先设置成非阻塞的,读取时就会大量返回EAGAIN错误。看来行为和文档并不一样。

最后,我把代码改为在epoll通知可读时再读取并解析,故障消失。

后记:

早上在微博上顺手搜了一下,发现也有人已经掉过坑,但是我用google搜索时就没看到这个信息,看来对于新技术应该多做一些调研和试验才能放心用。

http://weibo.com/1457629002/AymKa8FeS?type=comment#_rnd1416450208506

相关修改

http://lists.openwall.net/netdev/2009/10/19/72

 

posted on 2014-11-19 21:46  chen3feng  阅读(580)  评论(0编辑  收藏  举报

导航