画图带你理清TCP协议三次握手和四次挥手(二)
2.超时重传
确认应答是比较理想的情况,但数据在传输过程中,可能是会丢包的
仍以上面例子为例,A 给 B 发消息,你在家嘛?等了很久,A 也没收到 B 的消息,此时,存在以下几种情况:
① B 不想回 A 的消息
② B 没收到 A 的消息 (丢包情况1: 发的请求丢失)
③ B 回复了消息,但 A 没收到 (丢包情况2: 应答的 ACK 丢失)
②③情况:丢包的两种情况,对于发送方来说无法确定是哪种情况,因此,进行统一处理:当发送了一条数据之后,TCP 内部就会自动启动一个定时器,达到一定时间也没收到 ACK,定时器就会自动触发重传消息的动作 —— 超时重传
①情况:
思考:
假设第二次重发没有成功,那么就存在两个超时时间 t1,t2 如图所示:
那么,t1 和 t2 时间一样长吗??
在 TCP 中,t2 会比 t1 更长
TCP 抱着一种 “悲观的态度”,当一次丢包重传之后,TCP 就觉得大概率后面的重传也没用,所以就隔一个更长的时间,节省带宽
上述丢包有两种情况,一种是请求丢失 —— 重传没有问题;一种是 ACK 丢失,重传就意味着接收方收到了相同的数据
TCP 会在内部进行数据去重 (以序号为 key 进行去重),保证应用层读到的数据不是重复数据
确认应答 和 超时重传是 TCP 可靠性中最核心的机制
3.建立连接 - 三次握手
为什么要就建立连接?
1.更好的保证可靠性: 建立连接的过程其实就是让通信双方验证各自的发送能力和接受能力是否正常
2.协商一些重要参数 (如: 序号的初始值)
具体怎样建立连接?
举例:A 给 B 打电话,打电话同样要验证自己以及对方的话筒和听筒是否正常工作
第一次握手:刚开始,A 不知道自己和 B 手机的听筒和话筒是否正常,所以 A说"喂,你能听到吗?"
第二次握手:B 听到后,说明 A 的话筒和 B 的听筒正常,但 B 还需进一步检查自己的话筒和 A 的听筒是否正常;同时 B 把 A 话筒正常和自己听筒正常的消息传递给 A;于是 B “我能听到,你呢?”
第三次握手:A 收到 B 的消息后,就证明了 A 听筒正常,B 话筒正常
以上三次握手就保证了 A、B 的听筒和话筒都正常,也就保证了通话的正常,这就类似于网络建立连接时的三次握手
TCP 中真实的建立连接过程:(假设主机 A 主动发起连接)
第一次握手:客户端向服务器发送 SYN 报文 (SEQ=x,SYN=1),并进入 SYN_SENT 状态,等待服务器确认
第二次握手:实际上是分两部分来完成的,即 SYN+ACK (请求和确认) 报文
服务器收到了客户端的请求,向客户端回复一个确认信息 (ack=x+1)
服务器再向客户端发送一个 SYN 包 (SEQ=y)建立连接的请求,此时服务器进入 SYN_RECV 状态
第三次握手:客户端收到服务器的回复 (SYN+ACK 报文0);此时,客户端也要向服务器发送确认包 (ACK);此包发送完毕客户端和服务器进入 ESTABLISHED 状态,完成 3 次握手
建立连接的过程,相当于通信双方各自给对方发送 SYN,在各自给对方发送给 ACK,只不过中间的 ACK 和 SYN 合二为一了,于是最后就是"三次握手"
几个重要的状态:
LISTEN: 正在侦听来自远方的 TCP 端口的连接请求,服务端启动后处于 LISTEN 状态用于监听不同客户端的 TCP 请求并建立连接
SYN_SEND / SYN_RCVD: 建立连接的中间过程,若连接顺利的话(建立连接过程也可能丢包),这两个状态就一瞬消失
ESTABLISHEN: 连接建立完毕 (验证了通信双方的发送和接受能力都正常),可以进行数据传输
文章转自公众号:三友的java日记