TCP头部
源端口和目的端口在TCP层确定双方进程,序列号表示的是报文段数据中的第一个字节号,ACK表示确认号,该确认号的发送方期待接收的下一个序列号,即最后被成功接收的数据字节序列号加1,这个字段只有在ACK位被启用的时候才有效。
当新建一个连接时,从客户端发送到服务端的第一个报文段的SYN位被启用,这称为SYN报文段,这时序列号字段包含了在本次连接的这个方向上要使用的第一个序列号,即初始序列号ISN,之后发送的数据是ISN加1,因此SYN位字段会消耗一个序列号,这意味着使用重传进行可靠传输。而不消耗序列号的ACK则不是。
头部长度(图中的数据偏移)以32位字为单位,也就是以4bytes为单位,它只有4位,最大为15,因此头部最大长度为60字节,而其最小为5,也就是头部最小为20字节(可变选项为空)。
三次握手四次挥手图例
三次握手是指发送了3个报文段,四次挥手是指发送了4个报文段。注意,SYN和FIN段都是会利用重传进行可靠传输的。
下图是TCP三次握手四次挥手的时序图:
下图为TCP协议状态机:
ACK —— 确认,使得确认号有效。
RST —— 重置连接(经常看到的reset by peer)就是此字段搞的鬼。
SYN —— 用于初始化一个连接的序列号。
FIN —— 该报文段的发送方已经结束向对方发送数据。
当一个连接被建立或被终止时,交换的报文段只包含TCP头部,而没有数据。
三次握手
要弄清TCP建立连接需要几次交互才行,我们需要弄清建立连接进行初始化的目标是什么。
TCP进行握手初始化一个连接的目标是:分配资源、初始化序列号(通知peer对端我的初始序列号是多少)。知道了初始化连接的目标,那么要达成这个目标的过程就简单了,握手过程可以简化为下面的四次交互:
- client端首先发送一个SYN包告诉Server端我的初始序列号是X。
- Server端收到SYN包后回复给client一个ACK确认包,告诉client说我收到了。
- 接着Server端也需要告诉client端自己的初始序列号,于是Server也发送一个SYN包告诉client我的初始序列号是Y。
- Client收到后,回复Server一个ACK确认包说我知道了。
整个过程4次交互即可完成初始化。
为什么要进行三次握手
客户端和服务端通信前要进行连接,“3次握手”的作用就是双方都能明确自己和对方的收、发能力是正常的。
第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。 从客户端的视角来看,我接到了服务端发送过来的响应数据包,说明服务端接收到了我在第一次握手时发送的网络包,并且成功发送了响应数据包,这就说明,服务端的接收、发送能力正常。而另一方面,我收到了服务端的响应数据包,说明我第一次发送的网络包成功到达服务端,这样,我自己的发送和接收能力也是正常的。
第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力,服务端的发送、接收能力是正常的。 第一、二次握手后,服务端并不知道客户端的接收能力以及自己的发送能力是否正常。而在第三次握手时,服务端收到了客户端对第二次握手作的回应。从服务端的角度,我在第二次握手时的响应数据发送出去了,客户端接收到了。所以,我的发送能力是正常的。而客户端的接收能力也是正常的。
经历了上面的三次握手过程,客户端和服务端都确认了自己的接收、发送能力是正常的。之后就可以正常通信了。
四次挥手
TCP进行断开连接的目标是:回收资源、终止数据传输。
由于TCP是全双工的,需要Peer两端分别各自拆除自己通向Peer对端的方向的通信信道。这样需要四次挥手来分别拆除通信信道,就比较清晰明了了。
- Client发送一个FIN包来告诉Server我已经没数据需要发给Server了。
- Server收到后回复一个ACK确认包说我知道了。
- 然后server在自己也没数据发送给client后,Server也发送一个FIN包给Client告诉Client我也已经没数据发给client了。
- Client收到后,就会回复一个ACK确认包说我知道了。
到此,四次挥手,这个TCP连接就可以完全拆除了。
为什么要进行四次挥手
TCP连接是双向传输的对等的模式,就是说双方都可以同时向对方发送或接收数据。
当有一方要关闭连接时,会发送指令告知对方,我要关闭连接了。这时对方会回一个ACK,此时一个方向的连接关闭。但是另一个方向仍然可以继续传输数据,等到发送完了所有的数据后,会发送一个FIN段来关闭此方向上的连接。接收方发送ACK确认关闭连接。
注意,接收到FIN报文的一方只能回复一个ACK, 它是无法马上返回对方一个FIN报文段的,因为结束数据传输的“指令”是上层应用层给出的,我只是一个“搬运工”,我无法了解“上层的意志”。
为什么握手是三次而挥手要四次
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定,因此,己方ACK和FIN一般都会分开发送。
##################