code_tin

流言终结者4 - TCP_DEFER_ACCEPT
想要提高TCP SERVER的性能(编程方面) 其中一个方法就是使用TCP_DEFER_ACCEPT来减少实际的E...
扫描右侧二维码阅读全文
28
2010/01

流言终结者4 - TCP_DEFER_ACCEPT

想要提高TCP SERVER的性能(编程方面)
其中一个方法就是使用TCP_DEFER_ACCEPT来减少实际的ESTABLISHED连接数
当一个链接还没有实际传输数据时,使用此参数设置socket将会只产生SYN_RECV状态的链接
不得不说网上资料抄袭现象严重,而且残缺不全
首先这个参数定义的头文件就没有提到
还有timeout值的说明也有问题
甚至有些例子代码连前面的IPPROTO_TCP都写成SOL_SOCKET

TCP_DEFER_ACCEPT
此宏定义在netinet/tcp.h
具体用法
#include int timeout=1; setsockopt( listen_fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, sizeof(int) )
具体解释
首先使用此选项设置监听端口的TCP属性
这样当监听端口接收到客户端的链接
不会直接丢给accept
而是在第一次接受到实际数据时才会建立真实链接

网上的几个误区
1.使用SOL_SOCKET
绝对的误人子弟,使用SOL_SOCKET进行设置的结果就是,调用函数无错误,但是实际效果是--没效果,任何连接上来就是ESTABLISHED
因为三次握手是TCP的属性
而不是SOCKET层面的额属性
所以要用IPPROTO_TCP

2.认为timeout就是连接上来几秒没数据就断开的时间
错!TCP链接并不会立刻断开
实际的超时时间是这么算的
当服务端一直没接受到数据后,会重发SYN/ACK给客户端
达到次数仍旧未接收到数据,才会开始timeout的计时
实际在CentOS 5.2下面大约是4分钟左右.

重发报文的次数在net.ipv4.tcp_synack_retries中定义
使用命令,我们可以看到CentOS默认的次数是5次
#sysctl -e net.ipv4.tcp_synack_retries net.ipv4.tcp_synack_retries = 5

3.在setsockopt时使用参数0
这样做是没有意义的,
如果你设置timeout为0,你会发现链接上来的客户端立即变为ESTABLISHED
因为0的含义应该是
取消前面设置的TCP_DEFER_ACCEPT
直接确认最后一个ack上来的消息

Last modification:November 26th, 2018 at 04:16 pm
If you think my article is useful to you, please feel free to appreciate

3 comments

  1. qiezi

    应该是SOL_TCP吧,它和IPPROTO_TCP的值都是6,从名字定义上来看,SOL_TCP似乎更合适,不过SOL_TCP在有些平台上没定义。

    补充:
    1)超时前,如果对端关闭,应用程序会收到监听端口的read事件,应用程序需要accept,当然马上就能知道该连接已经关闭了。感觉这个完全没有达到设计的效果(指的是减少无意义连接的开销)
    2)已经确认超时的,完全不需要抛给应用去处理吧,这么做,应用程序根本不知道有超时过,但它还是抛给应用程序了
    (以上两条是我测试的,感觉这个选项很鸡肋)
    3)超时以后它重发ack,就像是模拟丢包一样。如果对方回应,相当于确认超时,把事件丢到上层处理,如果再发生丢包就是重传了

    我粗浅的理解是它使用了一种最小成本的实现,可能只需要多使用一个flag,这个flag在超时发生时重发一个ack并它设置成正常状态,后面就和DEFER_ACCEPT选项无关了。这种实现很简单,导致实现效果不理想,并没有实现精确的超时和提高性能的目的。这只是猜测,还需要读代码

    有时间装个BSD测试一下SO_ACCEPTFILTER看看它的实现效果〜

  2. tclwp

    BSD上是这么用的 setsockopt(fd, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0)
    但是要将IPPROTO_TCP改为SO_ACCEPTFILTER

  3. tclwp

    SOL_SOCKET , 我怎么记得是在BSD上使用的选项呢
    LINUX的用IPPROTO_TCP

Leave a Comment