大家好,又见面了,我是你们的朋友全栈君。
确认应答是可靠传输的最核心机制 接收方反馈一个应答报文(ACK),表示已收到
假设现在 A 想去 B 家里玩游戏,于是 A 给 B 发消息,若消息没有出现错误且顺序正确 结果如下所示:
但网络传输比较复杂,可能存在一种情况”后发先至” 由于数据的长度不同或者传输网络不同,先发送的数据不一定先到达,接收方接收到的数据可能是乱序的,如图:
当 B 回复 A 的消息时,若存在对应关系,那么即使出现了”后发先至”的情况,也能顺利的确立应答
上述方法,虽然可以顺利的确立应答,但额外的信息很多,占用的带宽很多
下面如图,针对发送的请求进行编号,应答的时候也针对编号进行应答,这样既能保证数据传输没有歧义,也不会浪费太多的空间和带宽
序号和确定序号,在前面 TCP报文格式中提到过
上述情况不严谨,真实的 TCP 还不一样,TCP 是面向字节流的,此处的编号并不是按照一条两条来编的,而是按照字节来编号的 (每个字节有一个编号)
确认应答是一种特殊的报文(ACK),所谓的应答报文,本质上就是 ACK 字段为1 的报文,此时报头中的”确认序号”字段才是生效的
初始序号是随机的,为了防止网络攻击;如果发送多个数据,每个数据都会带着一个序号 接收方收到数据后,是知道数据所带着的序号的,根据序号给出确认序号(告诉发送方下次给我发的序号),发送给发送方,发送方就知道接收方收到了哪些数据
确认应答是比较理想的情况,但数据在传输过程中,可能是会丢包的
仍以上面例子为例,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 可靠性中最核心的机制
为什么要就建立连接? 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,在各自给对方发送给 ACK,只不过中间的 ACK 和 SYN 合二为一了,于是最后就是”三次握手”
几个重要的状态:
1.两次握手可以吗?? 不可以
.
2.为什么是三次?? 主要是为了建立可靠的通信通道,保证客户端与服务端同时具备发送、接收数据的能力 . 3.四次握手可以吗?? 可以,但没必要 四次握手可以验证双方的发送接收能力正常,但是这样做效率比较低 .
三次握手: 双方各自向对方发起建立连接的请求,再各自给对方回应,只不过,中间的 SYN 和 ACK 能合并在一起 四次挥手: 双方各自向对方发起建立连接的请求,再各自给对方回应,只不过,中间的 FIN 和 ACK 不一定能合并在一起
仍以打电话为例,如下图:
TCP 中真实的断开连接过程: (假设主机 A 主动断开连接)
两个重要的状态:
1.四次挥手,三次挥完行不行?? 通常情况下不行,若触发了延时应答机制,就可以三次挥完 “不行”,即:上述的 ② ③ 为什么没有合并在一起?? 因为中间两次操作的时机不一样 ACK 是收到 FIN 之后立刻由内核返回的数据报,FIN 是应用程序处理完接受缓冲区的数据之后,调用的 close 方法触发的 . 2.为什么四次?? 因为要确保客户端和服务端的数据能够完成传输 . 3.为什么 TIME_WAIT 状态要等待 2MSL?? 假设网络上传输数据的最大时间为 MSL MSL 就是 ACK / FIN 从主机 A 到主机 B 的最大时间 TIME-WAIT 等待时间,需要分成两个部分: ①等待 ACK 经历一个最大时间到达主机 B ②万一 ACK 丢了,在等待一个最大时间,主机 B 重传 FIN 到达主机 A 因此,TIME_WAIT 就需要等待 2倍的MSL,即:2MSL 原因:
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/137156.html原文链接:https://javaforall.cn