美文网首页
TCP/IP常见问题

TCP/IP常见问题

作者: 坤_7a1e | 来源:发表于2018-05-22 11:28 被阅读0次

    查看tcp各个状态个数

    $ netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 

     CLOSE_WAIT 1 

    TIME_WAIT 1 

    ESTABLISHED 31 

    LAST_ACK 16 

    SYN_SENT 6 

    SYN_RCVD 6 

    FIN_WAIT1 1 

    FIN_WAIT2 1 

    五元组

    源IP地址,源端口,目的IP地址,目的端口,和传输层协议这五个量组成的一个集合。 

    四元组

    源IP地址,源端口,目的IP地址,目的端口

    常用的三个状态

    ESTABLISHED 表示正在通信,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。

    如何避免time_wait状态

    服务器可以设置SO_REUSEADDR套接字选项来通知内核,如果端口忙,但TCP连接位于TIME_WAIT状态时可以重用端口。一个非常有用的场景是,如果你的服务器程序停止后想立即重启,而新的套接字依旧希望使用同一端口,此时SO_REUSEADDR选项就可以避免TIME_WAIT状态。

    TIME_WAIT状态如何产生

    TIME_WAIT 是主动关闭连接时形成的,等待2MSL时间,约4分钟。主要是防止最后一个ACK丢失。  由于TIME_WAIT 的时间会非常长,因此server端应尽量减少主动关闭连接;  RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。

    MSL就是maximum segment lifetime(段的最长寿命)报文最大生存时间,这是一个IP数据包能在互联网上生存的最长时间,超过这个时间IP数据包将在网络中消失 。

    首先客户端调用close()发起主动关闭的一方,在发送最后一个ACK之后会进入time_wait的状态,也就说该发送方会保持2MSL时间之后才会回到初始状态。产生这种结果使得这个TCP连接在2MSL连接等待期间,定义这个连接的四元组(客户端IP地址和端口,服务端IP地址和端口号)不能被使用。

    time_wait状态产生的原因

    1. 为实现TCP全双工连接的可靠释放 ,client必须进入 TIME_WAIT 状态,因为client可能面临重发最终ACK的情形。由于TCP协议的重传机制,执行被动关闭的一方(server)将会重发其FIN,在该FIN到达client之前,client必须维护这条连接状态,也就说这条TCP连接所对应的资源(client方的local_ip,local_port)不能被立即释放或重新分配,直到另一方重发的FIN达到之后,client重发ACK后,经过2MSL时间周期没有再收到另一方的FIN之后,该TCP连接才能恢复初始的CLOSED状态。如果主动关闭一方不维护这样一个TIME_WAIT状态,那么当被动关闭一方重发的FIN到达时,主动关闭一方的TCP传输层会用RST包响应对方,这会被对方认为是有错误发生,然而这事实上只是正常的关闭连接过程,并非异常。

    2. 为使旧的数据包在网络因过期而消失

    先假设TCP协议中不存在TIME_WAIT状态的限制,再假设当前有一条TCP连接:(local_ip, local_port, remote_ip,remote_port),因某些原因,我们先关闭,接着很快以相同的四元组建立一条新连接。TCP连接由四元组唯一标识,因此,在我们假设的情况中,TCP协议栈是无法区分前后两条TCP连接的不同的,在它看来,这根本就是同一条连接,中间先释放再建立的过程对其来说是“感知”不到的。这样就可能发生这样的情况:前一条TCP连接由local peer发送的数据到达remote peer后,会被该remot peer的TCP传输层当做当前TCP连接的正常数据接收并向上传递至应用层(而事实上,在我们假设的场景下,这些旧数据到达remote peer前,旧连接已断开且一条由相同四元组构成的新TCP连接已建立,因此,这些旧数据是不应该被向上传递至应用层的),从而引起数据错乱进而导致各种无法预知的诡异现象。作为一种可靠的传输协议,TCP必须在协议层面考虑并避免这种情况的发生,这正是TIME_WAIT状态存在的第2个原因。

    如果 TIME_WAIT 状态保持时间不足够长(比如小于2MSL),第一个连接就正常终止了。第二个拥有相同相关五元组的连接出现,而第一个连接的重复报文到达,干扰了第二个连接。TCP实现必须防止某个连接的重复报文在连接终止后出现,所以让TIME_WAIT状态保持时间足够长(2MSL),连接相应方向上的TCP报文要么完全响应完毕,要么被 丢弃。建立第二个连接的时候,不会混淆。

    CLOSE_WAIT

    CLOSE_WAIT是被动关闭连接是形成的。根据TCP状态机,服务器端收到客户端发送的FIN,则按照TCP实现发送ACK,因此进入CLOSE_WAIT状态。但如果服务器端不执行close(),就不能由CLOSE_WAIT迁移到LAST_ACK,则系统中会存在很多CLOSE_WAIT状态的连接。此时,可能是系统忙于处理读、写操作,而未将已收到FIN的连接,进行close。此时,recv/read已收到FIN的连接socket,会返回0。

    TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源不会被释放。网络服务器程序要同时管理大量连接,所以很有必要保证无用连接完全断开,否则大量僵死的连接会浪费许多服务器资源。在众多TCP状态中,最值得注意的状态有两个:CLOSE_WAIT和TIME_WAIT。  

    TIME_WAIT 和CLOSE_WAIT状态socket过多

    如果服务器出了异常,百分之八九十都是下面两种情况:

    1.服务器保持了大量TIME_WAIT状态

    2.服务器保持了大量CLOSE_WAIT状态,简单来说CLOSE_WAIT数目过大是由于被动关闭连接处理不当导致的。

    因为linux分配给一个用户的文件句柄是有限的,而TIME_WAIT和CLOSE_WAIT两种状态如果一直被保持,那么意味着对应数目的通道就一直被占着,而且是“占着茅坑不使劲”,一旦达到句柄数上限,新的请求就无法被处理了,接着就是大量Too Many Open Files异常,Tomcat崩溃。

    如果TIME_WAIT维持的时间过长

    主动关闭连接端迟迟无法关闭连接,占用程序资源。

    RST报文的作用

    使用RST报文跳过TIME_WAIT状态来释放一个连接

    异常终止一个连接,可以通过发送一个RST报文段而不是FIN报文段来中途释放一个连接,收到RST的一方将终止该连接,并通知应用层连接复位。

    服务器程序一直保持CLOST_WAIT状态

    如果服务器程序TCP连接一直保持在CLOSE_WAIT状态,那么只有一种情况,就是在对方关闭连接之后服务器程序自己没有进一步发出ack信号。换句话说,就是在对方连接关闭之后,程序里没有检测到,或者程序压根就忘记了这个时候需要关闭连接,于是这个资源就一直被程序占着。

    相关文章

      网友评论

          本文标题:TCP/IP常见问题

          本文链接:https://www.haomeiwen.com/subject/fhqhjftx.html