TCP/IP——TCP连接的建立与终止、TCP超时、TCP状态变迁、TCP复位

一、概述

TCP是一个面向连接的协议。无论哪一方想另一方发送数据之前,都必须现在双方之间建立一条连接。这种两端间连接的建立与无连接协议如UDP不同。一端使用UDP想另一端发送数据报时,无需任何预先的握手。
MSS:表示TCP传往另一端的最大块数据的长度。
窗口大小决定发送多少个MSS
而UDP中,大于MTU是需要分片

二、TCP连接的建立和终止的时间

在这里插入图片描述
在这里插入图片描述
发起连接(报文段1)的一方是主动打开,接受连接(报文段2)的一方是被动打开。

其中,双方的序号(ack)的初始值(ISN)都是根据自身主机的时钟随机生成的,这也可以在一定程度上防止通信数据被伪造。

无论是建立连接还是终止连接,都会消耗一个序号,这从SYN包中seq值及对SYN应答包中的ack值、FIN包的seq值及对FIN应答包中的ack值可以看出来。

注意:对于报文段2(服务端的SYN+ACK),同样会存在超时重传。

服务端在发送该报文段(报文段2)时,会启动超时重传定时器,定时器一到,就会重传。

报文段7,是对被动关闭一方的FIN包的确认包,发送该包的同时,主动关闭方进入time_wait状态,并启动2MSL定时器。

2MSL定时器是针对最后一个报文段(报文段7)而设置的。报文段7是客户端对服务端FIN包的确认,发送报文段7的时候,启动2MSL定时器,同时客户端进入time_wait状态。如果在2MSL超时之前未再收到任何数据包,则该连接进行释放。
为什么是2倍的MSL的时间 ?

MSL是指报文段的最大生存时间。发送报文段7时启动2MSL定时器,一方面是报文段7到达服务端的最长时间是1个MSL,另外,如果服务端在一定时间内未收到针对FIN包的应答,会再次发送一个FIN包,该FIN包到达客户端的最长时间也是1个MSL。因此,客户端设置了2MSL的定时器,如果这段时间内没有再收到FIN包,说明服务端已经接收到了对上次FIN包的应答。如果又收到了一个FIN包,说明上次发送的FIN包应答延时或丢失了。

为什么是2倍的MSL的时间?

假设A和B建立了连接。传送数据完成后,A主动关闭到B的连接,B回复A关闭连接的ACK。B发起断开连接,A收到B的断开连接请求后,发送ACK。之所以要2MSL的时间,是因为对于A发送给B断开连接的ACK,有可能会丢失,如果B收不到ACK,将会再次发送一个断开连接的包。这时A的ACK到B,和B重传的断开连接的包到A,其时间和最大值不超过2个MSL。所以是2MSL。在A发送给B的ACK后,启动2MSL定时器,如果在2MSL时间内未收到B重传的断开连接包,A就关闭该连接。这时连接才彻底释放。
另外,一定要弄明白2MSL定时器,是在A发送给B的FIN包ACK后启动的。


发送第一个SYN的一端将执行主动打开(active open)。接收这个SYN并发回下个一SYN的另一端执行被动打开(passive open)

建立一个连接需要三次握手,而终止一个连接要经过四次握手。这由TCP的半关闭(half-close)造成的。既然一个TCP连接时全双工,因此每个方向必须单独的进行关闭。这原则就是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向连接。当一端收到一个FIN,它必须通知应用层另一端已经终止了那个方向的数据传送。发送FIN通常是应用层进行关闭的结果。

收到一个FIN只意味着在这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。而这对利用半关闭的应用来说是可能的,尽管在实际应用中只有很少的TCP应用程序这样做。

首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。通常一方完成主动关闭而另一方完成被动关闭。

发送FIN将导致应用程序关闭它们的连接,这些FIN的ACK是由TCP软件自动产生的。

当一端为建立连接发送它的SYN时,它为连接选择一个初始序号。ISN随时间而变化,因此每个连接都将具有不同的ISN。RFC 793 【Postel 1981c】指出ISN可看作时一个32比特的计数器,每4ms加1.这样选择序号的目的在于防止网络中被延迟的分组在以后又被传送,而导致某个连接的一方对它作错误的解释。

初始化序列号(ISN),在开机的时候,它就有一个函数,每个操作系统不一样,来不断的增加初始序列号的值。因为它的最大值为2的32次方,所以当达到最大值后,会又从0开始计数。

当在T1时间客户端要向服务器建立TCP,发送三次握手,就需要发一个SYN包。这时客户端就会截取T1时间的ISN作为SYN包的序列号,当服务器收到SYN包,在T2时间要回送SYN,ACK的时候,它就会截取T2时间的ISN作为SYN的序列号。ACK序列号为T1时间的ISN+1.

三、syn攻击、连接建立的超时、数据包的超时重传

syn攻击

首先要明白:只有当三次握手(三个TCP数据包)正常完成后,这条连接才算是真正建立,状态为established。

SYN攻击是指发送方不断发送连接请求(第一个TCP包,SYN),待服务端发送回应(第2个TCP包,SYN+ACK),发送方收到服务端的回应后,却不再发送第3个TCP包。这样会造成服务端存在大量的打开的TCP连接(处于open状态,但并不是established状态),这样会消耗服务端大量的系统资源(Socket内核资源)。这就是SYN攻击。

服务端在收到客户端发来的SYN报文段后,会回复SYN+ACK报文段,此时这条连接已处于半打开状态,会将该半打开状态的连接放入一个队列。

需要注意的是,该回复的报文段(SYN+ACK)同样存在超时重传,如果一定时间内未收到客户端发来的ACK报文段,服务端则会重传SYN+ACK报文段。达到最大重传次数后,将该条半打开连接从队列中移除。

SYN攻击就是利用这个特点,不断发起SYN报文段,但却不回复对服务端SYN+ACK报文段的确认。造成服务端维护较多的半打开连接,消耗系统资源。而正常的连接请求,却因为资源不足而无法响应或响应缓慢。

发送方的实现方式有两种(使用WinPCap可实现):

  1. 发送使用真实的IP地址发关TCP连接请求,但在收到服务端回复后,不再发送第3个TCP包。

  2. 发送方再发送给TCP服务端的连接请求中,使用的是虚假的IP地址,这样服务端回复给了虚假的IP地址。

这两种方式,对服务端来说,TCP服务端在发送了第2个TCP包后,都会一直得不到应答,直到超时。服务端会维持大量的这种状态的SOCKET。


ASA的一个功能,随机初始化序列号扰乱。为什么需要扰乱初始化序列号,

  1. 一台PC它的ISN有自己的增长规律,如果它在ASA里面,有些攻击者他会不断的去连接PC,PC这时候就会不断的回复SYN,ACK。攻击者就能得到不同节点时间段的ISN,然后用这些不同时间段的ISN来计算出PC的ISN增长规律,通过判断ISN增长规律,攻击者就有可能判断出你的操作系统。

  2. 一台PC和某个主机已经建立了TCP连接,攻击者想做一个会话劫持,它需要伪装PC的IP地址、端口号、协议号。这些伪装了还是不行,还得知道你的序列号在什么范围。所以攻击者这时候也会通过多次探测来猜测ISN的增长规律,当得到ISN的增长规律会就会把PC干掉,攻击者自己连接到相应的主机。

所以ASA就要防止这些攻击者通过多次试探来获取PC的ISN增长规律,因为一旦PC的ISN增长规律被获取后,攻击者就可以对我的操作系统进行判断,而且还有可能造成更严重的会话劫持。所以ASA会对初始化序列号进行扰乱。

当PC在T1时刻发送SYN的时候,经过ASA,ASA会把T1时刻的ISN随机加一个数发走,在T2时刻发送SYN的时候,经过ASA,ASA又会把T2时刻的ISN随机加一个会减去一个数发走。由于ASA总是会在ISN的数上随机加上一个或者减去一个数,这样的话,攻击者在看你的ISN的时候就会觉得没有规律可寻。

连接建立的超时(SYN包的超时重传)

对于建立连接时,SYN包丢失,其重传间隔2倍方递增。当重传达到最大次数后,即发生丢包。默认是5次,间隔为 1s+2s+4s+8s+16s+32s=63s。Windows(win7)上的实现,是只重传两次(即总共3次),间隔为3s,6s。即在01秒发第1包,则04秒发重传包,10秒重传包。(SYN重传时间间隔,注意该时间间隔是OS实现时自身确定的,而与网络的实际状况(如畅通、拥塞)等无关)

数据包的超时重传

对于数据包(ACK包不是数据包),也会超时重传,在发生超时重传时,TCP不是以固定的时间间隔来重传的,而是会再每次重传时都将下一次重传的间隔设置为上次重传间隔的2倍,因此重传间隔是倍数增加的。直到收到确认或者彻底失败。由于正常发送报文段时,重传定时器的超时值为EstimateRTT + 4 * DevRTT,因此第一重传时会将下一次的超时时间设置为2倍的该值,依次类推。

TCP数据包重传的次数也根据系统设置的不同而有区分,有些系统,一个报文只会被重传3次,如果重传三次后还未收到该报文的确认,那么就不再尝试重传,直接reset重置该TCP连接,但有些要求很高的业务应用系统,则会不断的重传被丢弃的报文,以尽最大可能保证业务数据的正常交互。

四、TCP的半关闭和半打开

TCP的半关闭和半打开

在这里插入图片描述
注意,处于半关闭状态的TCP连接,未主动断开过的一方仍可向另一方发送数据,接收到数据的一方,仍需要向发送方回复ACK。

处于半关闭状态的TCP连接,断开的一方,不能再主动去发送数据了。

半打开连接:

A和B建立过连接,但B崩溃了,这时叫半打开连接。这时,A向B发任何数据,B都将回复RST包。

五、TCP的状态变迁图

在这里插入图片描述

图中,椭圆框中的都是TCP的各个状态。其中,进入time_wait状态时,启动2MSL定时器。

注意,无论是哪一端,主动发起断开连接的一方(指的是第一次主动断开连接的一方),在双方都发送FIN包后,必须等待2MSL的时间。在这个2MSL的时间内,该方的端口号(本次使用的)不能被再次使用。但该选项可以被关闭。

同时可以看出,在关闭连接时,主动发起断开连接的一方(指的是第一次主动断开连接的一方),会最后进入CLOSE状态。而被动断开连接的一方(指的是第一次被动),先进入CLOSE状态。
在这里插入图片描述

2MSL等待状态

T I M E _ WA I T状态也称为 2 M S L等待状态。每个具体 T CP实现必须选择一个报文段最大生存时间M S L( Maximum Segment Lifetime)。它是任何报文段被丢弃前在网络内的最长时间。

RFC 793 [Postel 1981c] 指出MSL为2分钟。然而,实现中的常用值是30秒, 1分钟,或2分钟。总之,MSL是一个由OS指定的值,而不是根据网络的实际情况计算出来的。

对一个具体实现所给定的 M S L值,处理的原则是:当 T C P执行一个主动关闭,并发回最后一个 A C K,该连接必须在 T I M E _ WA I T状态停留的时间为 2倍的M S L。这样可让 T C P再次发送最后的A C K以防这个A C K丢失(另一端超时并重发最后的 F I N)。

这种2 M S L等待的另一个结果是这个 T C P连接在 2 M S L等待期间,定义这个连接的插口

(客户的 I P地址和端口号,服务器的 I P地址和端口号)不能再被使用。这个连接只能在 2 M S L结束后才能再被使用。

无论是客户端还是服务端,对于主动发起断开连接的一方,总是需要等待2MSL的time_wait的时间。如果主动发起断开连接的一方,断开连接后重启程序,如果还在2MSL的time_wait的时间内,则发起断开连接的一方的该端口不能被再次使用。

这时会引发一个问题:

1.如果发起断开连接的这一方是客户端,通常客户端不需要指定本地端口号,在断开连接后,重启程序,会重新随机选择一个本地端口再去连接服务器。客户端程序正常。

2.如果发起断开连接的这一方是服务端,通常服务端使用熟知的(固定的)监听端口号,在断开连接后,重启程序,服务端监听本地端口会失败,会提示端口被使用。这是因为该端口在上次主动断开连接后,还处理2MSL的time_wait状态。解决方法是设置监听端口的SO_REUSEADDR选项。注意:即使服务端设置了SO_REUSEADDR选项,使用服务端可以重用处理time-wait状态的端口,但仍不允许存在相同的连接。什么意思呢?

例如,服务器S 3.3.3.3 监听 3000端口,客户端 4.4.4.4,端口4000连接到S。这时,S主动断开连接,然后,重启了服务(服务端SOCKET设置了SO_REUSEADDR选项)。这时,如果客户端仍使用4000去建立连接,仍会提示连接失败

平静时间

对于来自某个连接的较早替身的迟到报文段,2MSL等待课防止将它解释成使用相同插口对的新连接的一部分。但这只有在处于2MSL等待连接中的主机处于正常工作状态时才有效。

如果使用处于2MSL等待端口的主机出现故障,它会在MSL秒内重新启动,并立即使用故障前仍处于2MSL的插口对来建立一个新的链接吗?如果这样,在故障前从这个连接发出而迟到的报文段会被错误地当作属于重启后新连接的报文段。无论如何选择重启后新连接的初始序号,都会发生这种情况

为了防止这种情况,RFC 793指出TCP在重启后的MSL秒内不能建立任何连接。这就称为平静时间。

只有极少的现实版遵守这一原则,因为大多数主机重启的时间都比MSL秒要长。

FIN_WAIT_2状态

在FIN_WAIT_2状态我们已经发送出了FIN,并且另一端也已对它进行确认。除非我们在实行半关闭,否则将等待另一端的应用层意识到它已收到一个文件结束符说明,并向我们发送一个FIN来关闭另一方向的连接。只有当另一端的进程完成这个关闭,我们这段才会从FIN_WAIT_2状态进入TIME_WAIT状态

这意味着我们这端可能永远保持这个状态。另一端也将处于CLOSE_WAIT状态,并一直保持这个状态直到应用层决定进行关闭。

在ASA中,ASA认为这样会消耗客户端资源。ASA发现只要有一边做了FIN,并在一定时间内,远端并没有再来发送一个FIN来进行关闭的话,那么ASA将发送一个RST置位把客户端的资源给释放掉。

七、TCP的复位报文段(RST)

无论何时一个报文段发往基准的连接(referenced connection)出现错误, T C P都会发出一个复位报文段(“基准的连接”是指由目的 I P地址和目的端口号以及源 I P地址和源端口号指明的连接,即五元组)。以下是RST报文段产生的几种情况:

  1. 到不存在的端口的连接请求

目的端口没有进程正在未处于监听状态时,(1)对于 U D P,当一个数据报到达目的端口时,该端口没在使用,它将产生一个I C M P端口不可达的信息;(2)对于TCP,将产生RST复位报文。以下为抓包分析截图:

使用UDP发送数据到一个未在监听的端口时,目的主机会回复一个ICMP差错报文:端口不可达,如下:
在这里插入图片描述
使用TCP连接到一个未在监听的端口时,目的主机会重置该连接(RST标志)

2.异常终止一个连接

异常终止一个连接对应用程序来说有两个优点:( 1)丢弃任何待发数据并立即发送复位报文段;( 2) R S T的接收方会区分另一端执行的是异常关闭还是正常关闭。

R S T报文段中包含一个序号和确认序号。需要注意的是 R S T报文段不会导致另一端产生任何响应,另一端根本不进行确认。收到R S T的一方将终止该连接,并通知应用层连接复位。正常终止一个TCP连接需要发送4个包(4次分手)。而异常关闭一个TCP连接仅需要一个包,即发送一个RST复位包。

  1. 半打开状态的检测

A与B正常建立连接后,B异常掉线(如断电、程序崩溃等),这时A仍处于打开状态。B重启应用后,A使用原来连接向B发数据,将收到B回复的RST报文。

更多会产生RST报文的情况,请参考文章:http://blog.csdn.net/hik_zxw/article/details/50167703

八、同时打开、同时关闭、TCP选项

TCP选项

TCP头部的可选字段,一般是在建立连接(SYN包)时使用,用于通信双方的协商。可选部分结构如下:
在这里插入图片描述
每个选项的开始是1字节k in d字段,说明选项的类型。 k i n d字段为0和1的选项仅占1个字节。其他的选项在k i n d字节后还有le n字节。它说明的长度是指总长度,包括 k i n d字节和l e n字节。

M S S让主机限制另一端发送数据报的长度。接收端通告窗口大小时,一般最小值会为一个MSS的大小,如果小于该MSS的大小,则通告窗口一般会为0. 这样避免了发送方发送较小的报文段。

窗口扩大因子,用于通告窗口扩容。

九、TCP实现中的注意事项

在伯克利的T C P实现中采用以下规则:

  1. 正等待连接请求的一端有一个固定长度的连接队列,该队列中的连接已被 T C P接受

(即三次握手已经完成),但还没有被应用层所接受。

注意区分 T C P接受一个连接是将其放入这个队列,而应用层接受连接是将其从该队列

中移出。即:该队列中的连接已经完成了TCP的三次握手,即状态已经是ESTABLISHED,但应用程序尚未调用accept。应用程序调用accept就是将一个连接从队列中移除。

  1. 应用层将指明该队列的最大长度,这个值通常称为积压值 ( b a c k l o g )。它的取值范围是0 ~ 5之间的整数,包括0和5(大多数的应用程序都将这个值说明为 5)。

  2. 当一个连接请求(即S Y N)到达时, T C P使用一个算法,根据当前连接队列中的连接数来确定是否接收这个连接。

注意,积压值说明的是 T C P监听的端点已被T C P接受而等待应用层接受的最大连接数。这个积压值对系统所允许的最大连接数,或者并发服务器所能并发处理的客户数,并无影响。

其中,积压值表示的是已完成TCP的三次握手,处于ESTABLISHED状态的连接数。

最大连接数是指能够同时处理的连接个数。

以下这段摘自:http://www.zhihu.com/question/21043005/answer/29875541

“积压值”指的是backlog,最大连接数是最大能处理的连接数(accept了丢一边晾着是耍流氓)提高并发处理能力是门学问,不单是提高“最大连接数”,两点结论:backlog不能提高“最大连接数”backlog不宜设置过大举个栗子,假设我们的服务器是一个非常受欢迎的饭店:最大连接数就是这个饭店最大能容纳的顾客人数,backlog就是门外允许排队的最大长度。如果饭店点菜慢上菜也慢(服务器的处理不能满足要求),饭店将很快被被顾客坐满(最大连接数上限),门口排位如果无限排下去(backlog设置非常大),可能还不如告诉顾客现在人太多了,我们处理不过来,不过等会儿再来试试。想要提高服务质量只能通过提高翻桌率(服务器处理速度)来实现。

  1. 如果对于新的连接请求,该 T C P监听的端点的连接队列中还有空间,T C P模块将对 S Y N进行确认并完成连接的建立。但应用层只有在三次握手中的第三个报文段收到后才会知道这个新连接时。另外,当客户进程的主动打开成功但服务器的应用层还不知道这个新的连接时,它可能会认为服务器进程已经准备好接收数据了(如果发生这种情况,服务器的 T C P仅将接收的数据放入缓冲队列 )。
  1. 如果对于新的连接请求,连接队列中已没有空间, T C P将不理会收到的 S Y N。也不发回任何报文段(即不发回 R S T)。如果应用层不能及时接受已被 T C P接受的连接,这些连接可能占满整个连接队列,客户的主动打开最终将超时。

猜你喜欢

转载自blog.csdn.net/weixin_44233369/article/details/87881201
tcp