关于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.