TCP详解

总通信流程图

 

上图表明了tcp三次握手,四次挥手通信流程

一般来说,我们希望看到的状态只有ESTABLISHED,其它状态都是问题状态的,但是我们通过命令netstat –alt 能看到其它状态,常见的有CLOSE_WAIT,TIME_WAIT。下面就来说说为什么会看到这些问题状态,以及解决方法。

TCP挥手详细流程

挥手比握手复杂,再来一张更加清晰的挥手通信图

 

状态详解

LISTEN

状态为LISTEN,这个没什么好说的,服务端首先启动监听,如果这个状态有问题,要么就是端口重了,要么就是连网卡有问题。

SYN_SENT

主动建立连接的一方发送SYN请求后的状态

SYN_RECV

被动建立连接的一方接受到SYN包后,状态由LISTEN转为SYN_RECV,并发出ack和SYN

ESTABLISHED

连接建立成功

FIN_WAIT1

此状态表示主动关闭tcp连接的一方,发出了第一次挥手指令后直到接收到另一端响应的ack的状态。

当FIN_WAIT1过多

分析

·被动关闭的一方出现问题(可能是本身故障或者网络故障),没有接收到第一次挥手指令,从而主动关闭的一方没有接收到响应的ack

·可能是网络问题

·被动关闭方服务器负载过重,导致没有资源来发送ack

·可能受到了网络攻击,可以在防火墙中过滤该地址

解决思路

·查看被动关闭方是否正常,包括所在的网络环境是否正常

·检查本地网络环境

·如果是外来ip,则防火墙拉黑

CLOSE_WAIT

当被动关闭方接受到FIN包后,状态就转为CLOSE_WAIT,并回复FIN包的ack包。直到被动关闭方向主动关闭方发起FIN包,CLOSE_WAIT状态才会消失。

CLOSE_WAIT状态过多

分析

·主动关闭方出现故障,没有能力回复ack。有可能在回复之前已经关闭连接

解决思路

·在主动方关闭连接的时候,被动方接受到FIN,却没有关闭自己连接,有可能是代码问题,检查代码有没有漏关连接。

·减小被动方的连接超时时间,比如connectTimeout,readTimeout设置在1s以内

FIN_WAIT2

主动关闭方接受到了自己请求关闭的FIN包的ack后,状态由FIN_WAIT1转为FIN_WAIT2。直到接受到被动关闭方发来的关闭请求FIN包。

FIN_WAIT2数量过多

分析

·由于被动关闭方一直没有发来FIN包,导致主动关闭方一直处于FIN_WAIT2状态

·网络状态,是不是网络波动导致大量丢包

解决思路

·减小FIN_WAIT2的超时时间

在/etc/sysctl.conf中加入配置

#默认超时时间是240s

tcp_fin_timeout=30

·查看被动关闭方代码。有没有及时关闭

LAST_ACK

被动关闭方在响应主动关闭方的后,发出自己关闭请求的FIN包,此时状态由CLOSE_WAIT转为LAST_ACK

TIME_WAIT

在接收到被动关闭方的FIN包后,状态由FIN_WAIT2转为TIME_WAIT,并向被动关闭方发送ack包。此状态的意义在于,四次挥手已经接近尾声,为了防止被动关闭方没有接收到ack包的问题,主动关闭方只能多存活一段时间(2MSL max segment lifetime),这段时间内如果被动关闭方真的没有收到ack,则会再次发来FIN包,来要主动关闭方的ack。

TIME_WAIT数量过多

分析

·网络状态不稳定,导致连接重复断连

·连接关闭后释放不及时,没有重复利用

解决思路

·调整linux上的关于TCP TIME_WAIT的参数

在/etc/sysctl.conf文件中加入或修改

#详细解释参考相关配置

net.ipv4.tcp_tw_reuse=1

net.ipv4.tcp_tw_recycle=1

net.ipv4.tcp_max_tw_buckets=5000

CLOSED

被动关闭方在接受到ack之后,状态由LAST_ACK转为CLOSED,至此连接结束(当然主动关闭方还在苦苦等待,等待结束后也会转为CLOSED状态)。

意外退出

程序意外退出

当程序意外退出时,比如直接kill -9 $pid

linux内核会释放关于该进程的所有资源,会自动触发tcp的4次挥手,并成为主动关闭连接的一方。

服务器关闭

服务器关闭就没这么好运了,通常情况只会留给进程几秒的时间来做资源释放,并不能保证tcp能正常释放

相关配置

#设置tcp配置的文件

/etc/sysctl.conf

#配置完记得保存

/sbin/sysctl -p

配置

Key

默认

解释

net.ipv4.tcp_syncookies

0

表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭。

net.ipv4.tcp_tw_reuse

0

表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭。

net.ipv4.tcp_tw_recycle

0

表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。

net.ipv4.tcp_fin_timeout

240

表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间,可改为30s

net.ipv4.tcp_keepalive_time

60*60*2

表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,一般改为20分钟。

net.ipv4.ip_local_port_range

32768 61000

表示用于向外连接的端口范围。缺省情况下过窄:32768到61000,改为1024到65535。

net.ipv4.tcp_max_syn_backlog

1024

表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。

net.ipv4.tcp_max_tw_buckets

180000

表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。默认为180000,建议减小,避免TIME_WAIT状态过多消耗整个服务器的资源,但也不能太小,跟你后端的处理速度有关,如果速度快可以小,速度慢则适当加大,否则高负载会有请求无法响应或非常慢。

可改为5000再视情况而定

net.ipv4.tcp_synack_retries

5

三次握手的第二次交互,tcp_synack_retries 的值必须为正整数,并不能超过 255。因为每一次重新发送封包都会耗费约 30 至 40 秒去等待才决定尝试下一次重新发送或决定放弃。tcp_synack_retries 的缺省值为 5,即每一个连线要在约 180 秒 (3 分钟) 后才确定逾时.

net.ipv4.tcp_syn_retries

5

三次握手的第一次交互。对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃。不应该大于255,默认值是5,对应于180秒左右时间。(对于大负载而物理通信良好的网络而言,这个值偏高,可修改为2.这个值仅仅是针对对外的连接,对进来的连接,是由tcp_retries1 决定的)

net.ipv4.tcp_retries1

3

放弃回应一个TCP连接请求前﹐需要进行多少次重试。RFC 规定最低的数值是3﹐这也是默认值﹐根据RTO的值大约在3秒 - 8分钟之间。(注意:这个值同时还决定进入的syn连接)

net.ipv4.tcp_retries2

15

在丢弃激活(已建立通讯状况)的TCP连接之前﹐需要进行多少次重试。默认值为15,根据RTO的值来决定,相当于13-30分钟(RFC1122规定,必须大于100秒).(这个值根据目前的网络设置,可以适当地改小,我的网络内修改为了5)

参考资料

http://blog.csdn.net/largetalk/article/details/16863689

原文地址:https://www.cnblogs.com/ulysses-you/p/7266594.html