三次握手
重要字段
序号(sequence number):seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。seq表示发送方的报文的起始序列号,ack表示希望收到的报文的序列号,ack也等于之前收到的对方的seq+报文长度
确认号(acknowledgement number):ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,ack=seq+1。
标志位(Flags):共6个,即URG、ACK、PSH、RST、SYN、FIN等。具体含义如下:
URG:紧急指针(urgent pointer)有效。
ACK:确认序号有效。(为了与确认号ack区分开,我们用大写表示)
PSH:接收方应该尽快将这个报文交给应用层。
RST:重置连接。
SYN:发起一个新连接。
FIN:释放一个连接。
seq序号、ack序号:用于确认数据是否准确,是否正常通信。
标志位:用于确认/更改连接状态。
为什么是三次握手不是两次握手呢
第一个观点
引用《计算机网络》的内容:
防止已失效的连接请求又传送到服务器端,因而产生错误
如果不是出于这种担心,两次握手完全可以建立连接。正常情况下是,客户端发出连接请求,告知服务端自己的序列号。接收端接收到消息后,向客户端发送自己的序列号。这样连接就已经可以建立了。
再说异常情况,第一次握手失败,服务端收不到信号,自然没有第二次握手。这个时候客户端会重新发送第一次握手的信息,直到超时或者成功收到第二次握手信息。如果第二次握手失败,同样客户端会重新发送信号,直到建立连接或者成功为止。这样建立连接是不存在问题的,不是你说的两次握手建立不了连接。问题的根源就是教科书上说的,如果仅仅只有两次握手,如果客户端已经连接超时失败,放弃连接了。这个时候超时的信号又到了服务端,服务第二次握手,认为建立了连接,服务器资源就被浪费了。如果是三次握手,就不存在这个问题了。因为客户端已经放弃了,服务端是不会收到第三次握手的,不会误认为连接建立成功了
某博客上的观点
引出了 TCP 与 UDP 的一个基本区别, TCP 是可靠通信协议, 而 UDP 是不可靠通信协议。
TCP 的可靠性含义: 接收方收到的数据是完整, 有序, 无差错的。
UDP 不可靠性含义: 接收方接收到的数据可能存在部分丢失, 顺序也不一定能保证。
为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤
如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认
了实现可靠传输,发送方和接收方始终需要同步( SYNchronize )序号。 需要注意的是, 序号并不是从 0 开始的, 而是由发送方随机选择的初始序列号 ( Initial Sequence Number, ISN )开始 。 由于 TCP 是一个双向通信协议, 通信双方都有能力发送信息, 并接收响应。 因此, 通信双方都需要随机产生一个初始的序列号, 并且把这个起始值告诉对方。
TCP 协议规定SYN报文虽然不携带数据, 但是也要消耗1个序列号, 所以前两次握手客户端和服务端都需要向对方回复 x+1 或 y+1 。最后一次握手, 默认不消耗序列号的特点。
再说说四次挥手
为什么不是三次呢?
因为TCP是全双工通信的
在客服端第1次挥手时,服务端可能还在发送数据。
所以第2次挥手和第3次挥手不能合并。
如果省略第二次的话还会引发不必要的FIN重传
【个人理解:如果没有第二次挥手,那么对方还在发送数据,这时候会导致主动方以为请求没有送过去,所以重复的发送一个FIN包】
(1)第一次挥手 因此当主动方发送断开连接的请求(即FIN报文)给被动方时,仅仅代表主动方不会再发送数据报文了,但主动方仍可以接收数据报文。
(2)第二次挥手 被动方此时有可能还有相应的数据报文需要发送,因此需要先发送ACK报文,告知主动方“我知道你想断开连接的请求了”。这样主动方便不会因为没有收到应答而继续发送断开连接的请求(即FIN报文)。
(3)第三次挥手 被动方在处理完数据报文后,便发送给主动方FIN报文;这样可以保证数据通信正常可靠地完成。发送完FIN报文后,被动方进入LAST_ACK阶段(超时等待)。
(4)第四挥手 如果主动方及时发送ACK报文进行连接中断的确认,这时被动方就直接释放连接,进入可用状态。