计算机 · 2021年12月19日 0

TCP Socket Option

总结一下自己目前接触到的TCP socket option。可以通过以下方式获得更加准确、详细的关于这些选项的介绍和应用:

  • man 7 tcp查看linux自带的manuanl
  • 阅读Unix网络编程之类的圣经
  • 阅读linux源码
  • 读下nginx/apache之类的web服务器的源码和配置选项中关于TCP连接的部分

注意事项

  • socket选项的继承性
  • 设置socket option的时机

具体的TCP Socket Option

TCP_DEFER_ACCEPT

  • 对于客户端来说,指定这个选项就意味着:在三次握手的时候,先只发送syn和接受服务器的ack/syn,然后就等着客户端应用程序要发数据的时候才把三次握手里的第三个包(ack)发给服务器;
  • 对于服务器来说,只有在收到来自客户端的真正带数据的包后,才会把这个连接抛给应用程序(通过accept)
  • 设置了TCP_DEFER_ACCEPT选项并只完成了前面两个包的TCP连接处于TCP_SYN_SENT或者TCP_SYN_RECV状态。对于服务器来说,是处于TCP_SYN_RECV(好吧,我还没有去仔细确认),内核也会将这个连接放入ehash,只是分配给这个连接的并不是一个完全体的socket,而是一个request socket(好吧,又没有确认)。
  • TCP_DEFER_ACCEPT指定的是一个总超时时间,TCP会将其转换成重传超时次数,具体方法就是以内核设置的默认TCP_TIMEOUT_INIT作为第一次重传超时时间,然后每次重传后从TCP_DEFER_ACCEPT里减去这个超时时间,并把这个超时时间乘以2(指数退避,最多变成TCP_RTO_MAX),一直到这个TCP_DEFER_ACCEPT变为0为止。

有一篇关于TCP_DEFER_ACCEPT的博客,可以参考。

TCP保活定时器

在TCP连接长时间不传输数据的时候,我们可能会想要一个能够定时检测该TCP连接是否还有效的功能。TCP保活定时器这个特性并不是TCP specification所要求的,TCP specification只说如果实现了保活定时器,那么只有在应用程序确认开启该特性的时候才开启,并且其检测的间隔默认设置为2小时。这个检测间隔可以修改,但是确是一个全系统共用的值。TCP保活定时器具有以下缺点:

  • 可能在进行TCP保活检测的时候,网络正好出现临时性的问题,导致检测失败,从而导致该TCP连接被判定断开。实际上这个时候也不急着用该TCP连接传输连接传输数据,待网络恢复以后该TCP连接其实可以正常传输数据的
  • 消耗更多的带宽
  • 因为发了更多的包,运营商会收取更多的费用

TCP保活定时器的优点

  • 对于一些服务器来说,需要能够及时释放无效的TCP连接的相关资源,如果客户端没有处理好这个问题,那么只能依靠服务器来做保活检测找到这些无效连接
  • TCP层面的保活检测比应用程序自己实现的保活检测消耗更少的带宽和资源(当然也存在着系统所有TCP连接都得使用同一个间隔这样尴尬的问题)

TCP保活定时器使用教程

阅读这篇文档,可以大致了解到SO_KEEPALIVE选项的用法,和如何设置与该选项相关的3个参数。

TCP Repair

为了支持容器中应用的热迁移,TCP实现了TCP_REPAIR特性,可以在迁移之前获取一个TCP连接的内部状态,然后在迁移后根据这些内部状态将一个新的TCP套接字改造成迁移之前的那个TCP连接。

具体使用方法可以学习github上的这份实例代码。要点如下:

  • 在建立套接字后,需要先通过setsockopt进入TCP_REPAIR模式,然后再通过setsockopt/getsockopt设置/获取相应参数;
  • TCP_REPAIR_QUEUETCP_SEND_QUEUETCP_RECV_QUEUE选项用于设置发送/接收队列;
  • TCP_REPAIR_WINDOW用于设置flow control的window等;