TCP/IP详解卷1 读书笔记:第十八章 TCP连接的建立与终止

来源:互联网 发布:淘宝运营公司那家强 编辑:程序博客网 时间:2024/06/05 04:06

 

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,将会再次发送一个断开连接的包。这时AACKB,和B重传的断开连接的包到A,其时间和最大值不超过2MSL。所以是2MSLA发送给BACK后,启动2MSL定时器,如果在2MSL时间内未收到B重传的断开连接包,A就关闭该连接。这时连接才彻底释放。

另外,一定要弄明白2MSL定时器,是在A发送给BFINACK后启动的。

 

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报文段的确认。造成服务端维护较多的半打开连接,消耗系统资源。而正常的连接请求,却因为资源不足而无法响应或响应缓慢。

以上三段根据百度百科(“SYN攻击”)的理解。


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

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

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

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

 

连接建立的超时(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头部的可选字段,一般是在建立连接(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的半关闭和半打开

半关闭连接:

A和B建立过双向连接,A关闭了向B发送数据的通道(B仍可向A发送数据,且A仍会回复B数据的ACK),这时的状态叫半关闭连接。


注意,处于半关闭状态的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去建立连接,仍会提示连接失败。

 

实验测试


客户端使用指定端口连接服务端,主动断开连接后,再次使用该端口去连接该服务端,出现错误。因为,该端口还处于time_wait状态,需要等待2MSL定时器超时。

但如果这时,再使用该端口4001去连接其他的服务器(IP),则仍可使用该端口。如下:

 

这表明,其实不能复用的是连接(即五元组),而非端口号。上图表明,两个连接可以使用同一个端口号,且其中一个连接处于time_wait状态。

 

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复位包。

 

3.      半打开状态的检测

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

 

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

 

TCP实现中的注意事项

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

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

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

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

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

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

3) 当一个连接请求(即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设置非常大),可能还不如告诉顾客现在人太多了,我们处理不过来,不过等会儿再来试试。想要提高服务质量只能通过提高翻桌率(服务器处理速度)来实现。

 

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

5) 如果对于新的连接请求,连接队列中已没有空间, T C P将不理会收到的 S Y N。也不发回任何报文段(即不发回 R S T)。如果应用层不能及时接受已被 T C P接受的连接,这些连接可能占满整个连接队列,客户的主动打开最终将超时。

 

0 0