关于TCP的三次握手和四次挥手的分析

  • 在网络分析中,读懂TCP序列号和确认号的值,可以帮助我们学习TCP协议以及排查问题,如通过查看序列号和确认号可以确定数据传输是否乱序。
  • TCP通讯中主要有连接的建立、数据的传输、连接的关闭三个过程。每个过程完成不同的工作,而且序列号和确认号在每个过程中的变化都是不同的。
  • TCP协议工作在传输层,是一种可靠的面向连接的数据流协议。TCP之所以可靠,是因为它保证了传送数据包的顺序。顺序是用一个序列号来保证的。

TCP报文格式详解:

https://blog.csdn.net/mary19920410/article/details/58030147

对于seq和ack的理解:

seq是序列号,这是为了连接以后传送数据用的(当然链接的时候也用),

ack是对收到的数据包的确认,值是等待接收的数据包的序列号。

第一次消息发送中,A随机选取一个序列号x作为自己的初始序号发送给B;

第二次消息B使用ack对A的数据包进行确认,因为已经收到了序列号为x的数据包,准备接收序列号为x+1的包,所以ack=x+1,同时B告诉A自己的初始序列号,就是seq=y;

第三条消息A告诉B收到了B的确认消息并准备建立连接,A自己此条消息的序列号是x+1,所以seq=x+1(即按照规矩就是上面ack的值),而ack=y+1是表示A正准备接收B序列号为y+1的数据包。

seq是数据包本身的序列号;

ack是期望对方下一个发送的数据包的序列号。

对于FLAGS字段表示的理解:

在TCP层,有个FLAGS字段,这个字段有以下几个标识:SYN, FIN, ACK, PSH, RST, URG.(6个)

SYN(synchronous建立联机) 表示建立连接

ACK(acknowledgement 确认) 表示响应

PSH(push传送) 表示有 DATA数据传输

FIN(finish结束) 表示关闭连接

RST(reset重置) 表示连接重置。

URG(urgent紧急)

  • 其中,ACK是可能与SYN,FIN等同时使用的,比如SYN和ACK可能同时为1,它表示的就是建立连接之后的响应,
  • 如果只是单个的一个SYN,它表示的只是建立连接。
  • 当出现SYN和SYN+ACK包时,我们认为客户端与服务器建立了一个连接。TCP的几次握手就是通过这样的ACK表现出来的。
     
  • 但SYN与FIN是不会同时为1的,因为前者表示的是建立连接,而后者表示的是断开连接。
     
  • RST一般是在FIN之后才会出现为1的情况,表示的是连接重置。
     
  • 一般地,当出现FIN包或RST包时,我们便认为客户端与服务器端断开了连接;
     
  • PSH为1的情况,一般只出现在 DATA内容不为0的包中,也就是说PSH为1表示的是有真正的TCP数据包内容被传递。

关于SYN攻击的理解:

SYN攻击属于DDOS(即分布式拒绝服务)的一种,

通过向目标主机发送大量的半连接请求(即SYN请求)并且伪装源IP和源端口,

使目标主机响应繁复的响应情况中(由于源IP为虚假IP,即显示中不存在,在目标主机回应了SYN+ACK报文后,由于没有等到请求主机的响应,目标主机启动重传机制,)

在反复发送后,达到一定的限制即放弃重发,使目标主机限于网络堵塞

三次握手过程:

一个虚拟连接的建立是通过三次握手来实现的

当客户端B,向服务器端A请求建立连接时:

1.两端首先都处于close状态;然后服务器端A打开,处于监听状态LISTEN,表示可建立连接。

2.然后B首先向A发送一个SYN报文,并置报文中的标记SYN=1,发送序号seq=X【这个X首次是随机生成的】;然后B端进入SY_SENT状态。

(此时报文中ACK标识,和ack确认号,没有说明就是都为0)

3.A端正确接收到B端的这个报文后,向B端回复一个对SYN报文的确认报文,即SYN+ACK报文,并置标记SYN和ACK都为1,发送序号seq=Y【这个首次也是随机生成的】,确认号ack=X+1;然后A端进入SYN_RCVD状态

4.B端正确接收到A端返回的报文后,再向A端发送一个ACK报文,通知A,连接已建立,并置其中标记ACK为1,发送序号seq=X+1,确认号=Y+1;然后B端进入ESTABLISHED状态

5.A端收到B发送过来的报文后,也进入ESTABLISHED状态

自此,客户端进和服务器通过TCP协议中的三次握手,建立好了链接。

当三此握手完成、连接建立以后,TCP连接的每个包都会设置ACK位

【再次梳理如下】

1. (B) –> [SYN] –> (A)

假如服务器A和客户机B通讯. 当A要和B通信时

B首先向A发一个SYN (Synchronize) 标记的包,告诉A请求建立连接.

注意: 一个 SYN包就是仅SYN标记设为1的TCP包(参见TCP包头Resources). 认识到这点很重要,

只有当A受到B发来的SYN包,才可建立连接,除此之外别无他法。

因此,如果你的防火墙丢弃所有的发往外网接口的SYN包,那么你将不能让外部任何主机主动建立连接。

2. (B) <– [SYN/ACK] <–(A)

接着,A收到后会发一个对SYN包的确认包(SYN/ACK)回去,表示对第一个SYN包的确认,并继续握手操作.

注意: SYN/ACK包是仅SYN 和 ACK 标记为1的包.

3. (B) –> [ACK] –> (A)

B收到SYN/ACK 包,B发一个确认包(ACK),通知A连接已建立。

至此,三次握手完成,一个TCP连接完成

Note: ACK包就是仅ACK 标记设为1的TCP包.

需要注意的是当三此握手完成、连接建立以后,TCP连接的每个包都会设置ACK位

【举例说明】

握手阶段:

序号      方向            seq           ack                               

1      A->B          10000          0

2           B->A          20000          10000+1=10001

3          A->B          10001          20000+1=20001

数据传输阶段:

序号  方向   seq               ack                                              size

23          A->B          40000          70000                                           1514

24          B->A          70000          40000+1514-54=41460                   54

25          A->B          41460          70000+54-54=70000                   1514

26          B->A          70000          41460+1514-54=42920                   54

握手阶段解释:

1:A向B发起连接请求,以一个随机数初始化A的seq,这里假设为10000,此时ACK=0

2:B收到A的连接请求后,也以一个随机数初始化B的seq,这里假设为20000,意思是:你的请求我已收到,我这方的数据流就从这个数开始。B的ACK是A的seq加1,即10000+1=10001

3:A收到B的回复后,它的seq是B的ACK+1【大小就是它的上个请求的seq加1】,即10000+1=10001,意思也是:你的回复我收到了,我这方的数据流就从这个数开始。A此时的ACK是B的seq加1,即20000+1=20001

数据传输阶段解释:

23:B接收到A发来的seq=40000,ack=70000,size=1514的数据包

24:于是B向A也发一个数据包,告诉B,你的上个包我收到了。

B的seq就以它收到的数据包的ACK填充,

ACK是它收到的数据包的SEQ加上数据包的大小(不包括以太网协议头,IP头,TCP头),

以证实B发过来的数据全收到了。

25:A在收到B发过来的ack为41460的数据包时,一看到41460,正好是它的上个数据包的seq加上包的大小,就明白,上次发送的数据包已安全到达。

于是它再发一个数据包给B。

这个正在发送的数据包的seq也以它收到的数据包的ACK填充,

ACK就以它收到的数据包的seq(70000)加上包的size(54)填充,即ack=70000+54-54(全是头长,没数据项)。

其实在握手和结束时确认号应该是对方序列号加1,

传输数据时则是对方序列号加上对方携带应用层数据的长度.

如果从以太网包返回来计算所加的长度,就嫌走弯路了.

另外,如果对方没有数据过来,则自己的确认号不变,

序列号为上次的序列号加上本次应用层数据发送长度.

TCP的三次挥手过程分析:

建立一个连接需要3个步骤,但是关闭一个连接需要经过4个步骤。

因为TCP连接是全双工的工作模式,所以每个方向上需要单独关闭。

在TCP关闭连接时,首先关闭的一方(即发送第一个终止数据包的)将执行主动关闭,而另一方(收到这个终止数据包的)再执行被动关闭。

关闭连接的4个步骤如下: 

1.主动方发送FIN+ACK报文,即报文中FIN标记和ACK标记都置为1;并且发送序号seq=X,确认号ack=Z;【和SYN一样,一个FIN将占用一个序号】

【序列号为客户端发送的上一个数据包中的确认号值;

而确认号为服务器发送的上一个数据包中的序列号+该数据包所带的数据的大小;】

2.被动方返回一个ACK报文,即报文中ACK标志被置为1;并且发送序号seq=Z(即上面接收到的确认号值),确认号ack=X+1(期待收到的下一个报文的序号);

3.被动方发送一个FIN+ACK报文,发送序号seq=Y,确认号ack=X【难以预测的ack】;

【序列号为服务器发送的上一个数据包中的确认号值,而确认号为客户端发 送的上一个数据包中的序列号+该数据包所带数据的大小】

4.主动方返回一个ACK确认报文,发送序号seq=X,ack=Y+1

百度百科分析:

连接终止协议(四次挥手)

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

(1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送

(2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。

(3) 服务器关闭客户端的连接,发送一个FIN给客户端。

(4) 客户端发回ACK报文确认,并将确认序号设置为收到序号加1。

状态分析

CLOSED:

表示初始状态。

LISTEN

这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。

SYN_RCVD:

这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。

SYN_SENT:

这个状态与SYN_RCVD遥相呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。

ESTABLISHED:

这个容易理解了,表示连接已经建立了。

FIN_WAIT_1:

这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。

FIN_WAIT_2:

上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。【可能还会传数据,因此ack的结果很难预测】

TIME_WAIT:

表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。

CLOSING:

这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也就会出现CLOSING状态,表示双方都正在关闭SOCKET连接。

CLOSE_WAIT:

这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是查看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。

LAST_ACK:

这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。

相关问题:

1. 为什么连接的时候是三次握手,关闭的时候却是四次握手?

答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

2. 为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。

3.

.

4.

猜你喜欢

转载自blog.csdn.net/Ideaddxxpp/article/details/91870166
今日推荐