TCP三次握手调优

TCP(Transmission Control Protocol)传输控制协议是一种面向链接的、可靠的、基于字节流的传输层协议。从TCP的定义中能够看出,TCP是面向链接的可靠的通讯方式,链接双方都须要肯定各自的链接通道都是OK的。三次握手的目的就是为了肯定各自的通道是OK的,同时通知对方本身的起始SEQ。当客户端调用connect函数时便发送了SYN报文同时通知对方本身的起始SEQ,从而发起第一次握手,客户端进入SYN_SENT状态;服务端收到SYN报文后,返回SYN+ACK报文到客户端同时通知对方本身的起始SEQ,从而发起了第二次握手,服务端进入SYN_RCV状态;客户端收到服务端的SYN+ACK后,回复ACK报文,从而发起第三次握手,客户端进入ESTABLISHED状态;服务端收到ACK报文后服务端进入ESTABLISHED状态。自此三次握手就完成了,其流程图以下:html

TCP的三次握手

过程以下:
image.png服务器

客户端调优

一、当客户端发起第一次握手的时候,若是迟迟收不到对方的应答,那么客户端会重试,重试的次数由/proc/sys/net/ipv4/tcp_syn_retries控制,默认值是5,重试间隔是1,2,4,8,16,32,总共须要花费63s。能够根据客户端与服务端的网络情况以及服务端的负载,适当下降重试次数调小,如2次,从而出现异常的时候,客户端能够尽快感知到异常。cookie

服务端调优

一、当服务端发起第二次握手的时候,若是迟迟收不到对方的应答,那么服务端也会重试,重试的次数由/proc/sys/net/ipv4/tcp_synack_retries控制,默认值是5,重试间隔是1,2,4,8,16,32,总共须要花费63s。一样的,若是客户端与服务器的网络情况挺好的,能够把重试次数调小。
二、当服务端发起第二次握手后,会把链接放入到半链接队列,队列的大小由/proc/sys/net/ipv4/tcp_max_syn_backlog控制,默认大小是2048。当这个队列满时,服务器将没法创建链接。那么咱们怎么知道这个队列是否有溢出呢?能够经过以下的命令看到网络

netstat -s | grep 'SYNs to LISTEN'
75571 SYNs to LISTEN sockets ignored

这个是个累计值,若是发现这个值不断的变大,能够把这个队列调大。同时还能够设置/proc/sys/net/ipv4/tcp_syncookies=1,打开tcp_syncookies功能。tcp_syncookies能够取以下的值:
A. tcp_syncookies=0时,关闭syncookies功能,当半链接队列满时,服务端将没法创建链接;
B. tcp_syncookies=1时,当半链接队列满时,服务端将启用syncookies功能;
C. tcp_syncookies=2时,服务端将一直启用syncookies功能。
tcp_syncookies的主要工做流程以下:
服务端接收到SYN报文并返回TSYN+ACK报文时,不插入半链接队列,而是根据这个SYN报文计算出一个cookie值。这个cookie做为将要返回的SYN ACK报文的初始序列号。当客户端返回一个ACK报文时,根据报文头信息计算cookie,与返回的确认序列号(初始序列号+1)进行对比,若是相同,则是一个正常链接,而后将链接放入accept队列。
若是经过netstat -lap发现SYN_RCV状态的链接不断的增加,那么就须要经过抓包工具分析是否是发生了syn泛洪攻击,若是发生了泛洪攻击,须要经过防火墙阻止这种链接。
所谓的SYN泛洪攻击利用的是TCP的三次握手机制,攻击端利用伪造的IP地址向被攻击端发出请求,而被攻击端发出的响应报文将永远发送不到目的地,那么被攻击端在等待关闭这个链接的过程当中消耗了资源,若是有大量的这种链接,主机资源将被耗尽,从而达到攻击的目的。
三、当服务端收到第三次握手的ACK应答报文后,服务端会把链接放入accept队列,accept队列由listen()函数传入的参数(参数的值能够经过ss -lnt命令的输出“Send-Q”列查看)与/proc/sys/net/core/somaxconn共同控制,取2者的小值。能够经过以下的命令查看是否由溢出:socket

netstat -s | grep overflow
75571 times the listen queue of a socket overflowed

若是这个值不断的变大,说明应用程序没有及时的调用accept函数接收链接,能够先调高上文提升的2个参数。
accept队列满后是否丢弃链接,是由参数/proc/sys/net/ipv4/tcp_abort_on_overflow控制,默认是0。若是设置为1而且溢出,则发送RST报文关闭链接。通常建议设置为0,由于丢弃后,客户端若是发送了数据+ACK,因为等不到应答,那么就会重复发送数据+ACK,当服务端接收到ACK后,若是accept队列不满了,那么链接就创建了。可见tcp_abort_on_overflow=0,能够提升TCP链接创建成功的几率。只有accept队列长期溢出的时候,才设置tcp_abort_on_overflow=1。
四、另外还能够打开TFO功能,提升TCP链接创建的效率,TFO详见文档:
https://tools.ietf.org/html/r...
https://www.cnblogs.com/passz...tcp