一. TCP概述
通过TCP/IP协议的学习,我们可以了解到--TCP是一种面向连接的、可靠的、基于字节流的通信协议,数据在传输前要建立连接(三次握手),传输完毕后要断开连接(四次握手)。
二. TCP三次握手
- TCP头部结构:
1 序号:Seq序号(32位),用来标识从计算机A发送到计算机B的数据包的序号,计算机发送数据时对此进行标记。
2 确认号:Ack确认号(32位),Ack = Seq + 1。
3 标志位:每个标志位占用1Bit,分为 URG、ACK、PSH、RST、SYN、FIN,具体含义如下:
SYN:同步序列编号,在建立连接时发送
ACK:确认序号有效
FIN:断开一个连接
PSH:接收方应该尽快将报文交给应用层
RST:重置连接
URG:紧急指针有效
- 三次握手过程:
① 客户端给服务端发一个 SYN 报文,并指明客户端的初始 化序列号
② 服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且指定了自己的初始化序列号
③ 客户端收到 SYN 报文之后,会发送一个 ACK 报文
过程如图:
发送第一个SYN的一端将执行主动打开,接收这个SYN并发回下一个SYN的另一端执行被动打开。
三. TCP四次挥手
TCP 连接的拆除需要发送四个包,因此称为四次挥手。
客户端发起关闭请求,四次挥手的过程:
- 客户端发送一个 FIN 报文,报文中会指定一个序列号,客户端进入FIN_WAIT_1状态。
- 服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明收到客户端的报文,Server进入CLOSE_WAIT状态。
客户端收到服务端的确认报文后进入FIN_WAIT_2状态。 - 若服务端也想断开连接,和客户端的第一次挥手相同,发送 FIN 报文,服务端进入LAST_ACK状态,等待客户端最后确认。
- 客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,把服务端的序列号值 +1 作为自己 ACK 报文的序列号值,然后进入到TIME-WAIT状态,服务端收到客户端的ACK后立即进入CLOSED状态(请注意:现在TCP连接还没有释放掉。必须经过时间等待计时器设置的时间2MSL(MSL:最长报文段寿命)后,客户端才进入到CLOSED状态,完成四次挥手)。
过程如图:
四. 实例监测
tcpdump
之前暑假写过聊天室,就用聊天室在本机来测试三次握手
因为都是在本机同时运行client和server所以命令为:
tcpdump -i lo port 4508 -S,
使用tcpdump观察如下:从tcpdump的数据,可以明显的看到三次握手的过程是:
第一次握手:
client SYN = 1, Seq = 2341371368 —> server
第二次握手:
server SYN = 1,Seq = 2511815235;
ACK = 1, ack = 2341371368 + 1 —> client
第三次握手:
client ACK = 1, ack = 2511815235 + 1 -->server
五. 补充问题
- 为什么需要三次握手?
第一次握手:客户端发送网络包,服务端收到。
客户端的发送、与服务端的接收正常
第二次握手:服务端发包,客户端收到。
服务端的接收、发送,与客户端的接收、发送正常。
但服务器并不确认客户端的接收能力是否正常。
第三次握手:客户端发包,服务端收到。
服务器发送、接收能力正常。 - 为什么需要四次挥手?
首先,当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。
其次,关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。
所以,只有等到Server端所有的报文都发送完了,client端才能发送FIN报文,因此不能一起发送。
参考以下文章:
TCP三次握手详解-深入浅出(有图实例演示)
面试官,不要再问我三次握手和四次挥手
我终于搞懂了TCP的三次握手和四次挥手(图片案例超详解)