JavaEE 初阶第二十二期:网络原理,底层框架的“通关密码”(二)
专栏:JavaEE初阶起飞计划
个人主页:手握风云
目录
一、TCP协议
1.1. TCP的核心机制
1.1.1. 超时重传
1.1.2. 三次握手
1.1.3. 四次挥手
一、TCP协议
1.1. TCP的核心机制
1.1.1. 超时重传
确认应答的关键是数据顺利到达,通过ACK报文发送给对方。但在实际传输过程中,可能会发生丢包。TCP的第二个核心机制就是超时重传,可以看作确认应答的重要补充,专门应对丢包的场景。
超时重传是两个过程:超时和重传。假设一个数据包,在传输过程中,丢包概率是10%,连续传输两次,数据包至少一次到达对方的概率是1-10%*10%=99%。随着传输次数的增加,数据报到达对方的概率大幅度增加。超时需要判断发送方是否出现丢包的条件。
我还是给别人发送信息,发送的信息会有一个最大等待时间,即超时时间。只要超过超时时间,还没有收到 ACK 就可以视为是丢包了。不同系统上,超时时间都是可能不同的,这个与可配置的参数有关。
没有收到ACK,分为两种情况:1. 发送的数据;2.应答报文。第一种情况出现了丢包只需重传。但是第二种情况,如果发生在转账环节,就会转两次。但TCP协议已经处理了上述情况。TCP 在接受到数据的时候,会在操作系统内核中维护一个“接收缓冲区"(内存空间)。如果又收到了同一个数据,此时就可以根据数据的序号来在接受缓冲区中进行"去重”,确保应用程序, 在进行 read 操作的时候,读到的数据不会出现重复。并且,TCP 也会针对收到的数据在接收缓冲区中进行重新排序,也能保证应用程序读取数据的时候读到的仍然是有顺序的数据。
超时重传的超时时间不是固定的,会发生动态变化。随着超时重传的进行,如果还是没有收到 ACK仍然要继续重传,但是等待的超时时间会逐渐变长。如果网络出现了严重故障,再频繁重传,非但不会解决问题,甚至可能会加重网络故障的程度。传次数和总的重传时间是存在上限的,达到了上限,重传还没有成功,TCP连接就会被"重置",也就是单方面的断开连接了。
1.1.2. 三次握手
TCP 的 “连接” 是指为实现可靠数据传输,通信双方(如客户端和服务器)通过特定流程建立的逻辑通信链路,各自保存对方的关键信息(IP、端口)。建立连接——三次握手;断开连接——四次挥手。
TCP 中的握手,传输一个“打招呼" 的数据包,这个数据包只有报头,没有正文,不携带任何"业务数据”。就如同在商务场合中,碰见了自己的朋友,先进行握手打招呼,寒暄过后,再谈合作。三次握手在建立连接过程中,客户端和服务器要经过三次这样的“打招呼”,连接才能在双方这边都建立好。
关键流程:
- 客户端给服务器发起一个 syn (同步报文段)。客户端告诉服务器:我要和你建立连接,请你保存我的信息。
- 服务器给客户端返回一个ack。服务器告诉客户端:收到,我会保存!
- 服务器也给客户端发起一个syn。服务器也要告诉客户端:我也要和你建立连接,请你保存我的信息。
- 客户端收到之后,也返回一个 ack。客户端告诉服务器: 收到,我会保存!
从流程或者逻辑上是四次交互,但是中间两次,可以合并成一个 TCP 数据包,整个过程只传输了三个数据包。
三次握手的意义:三次握手,也可以视为是一种"保证可靠传输的手段"(辅助手段)。
- 三次握手,相当于"投石问路",验证通信链路是否畅通。如同地铁站开放时,需要先运行一趟空车,确定路线是否通畅。
- 三次握手,也是在验证通信双方发送能力和接收能力是否正常。
- 通过三次握手,让通信双方协商关键信息。就像办婚礼,婆家人和娘家人需要一起商量,需要置办多少桌酒席。
TCP 建立连接过程中,有一个信息是需要协商的,就是 TCP 数据的起始序号。TCP 的序号,针对载荷部分按照字节编号。当 TCP 连接建立好了之后,传输的第一个数据包的第一个字节的编号,不是从 1/0 开始编排,而是在三次握手阶段协商出这样的数字作为起始编号。
编号之所以不从0开始,这样能够保证每次建立连接,协商出来的起始编号都是不同的,避免出现网络传输中的特殊情况。比如说,客户端和服务器建立连接后,想断开重启一下。其中某个数据因为网路的一些延迟“迷路了”,导致绕了很大一圈经过很长时间才到达服务器。当这个数据包终于到达服务器的时候,此时连接已经是其他的连接。那么服务器就得把这个数据包丢弃。
服务器如何区分是不是上一个连接发来的?每次重新建立连接,都会重新协商出起始序号,只需判断这个数据包的序号是不是很接近于当前连接的起始序号。
关于TCP建立连接需要三次握手。四次没必要,中间两次传输时机是相同的,合并成一次,有利于提升效率。两次,无法完成通信双方发送能力和接受能力的验证。
1.1.3. 四次挥手
断开连接的四次挥手,可能是客户端主动发起,也可能是服务器主动发起。而三次握手,一定是客户端先发起。
关键流程:
- 客户端告诉服务器,我要和你断开连接,请你把我删了。
- 服务器回应,收到!
- 服务器告诉客户端,我也要和你断开连接,请你把我也删了。
- 客户端回应,收到!
客户端和服务器都会把对方的信息(之前保存的对方的IP 和 端口) 删除掉,删除完了,连接就断开了。之所以叫做四次挥手,是因为中间两次交互,是不一定触发合并的。四次挥手和三次握手本质区别在于,四次挥手不是完全由操作系统内核完成的,而是和应用层代码有关系。
TCP有一个机制是延时应答,也就是应答ACK的时机会往后拖一会儿,比如,收到 FIN 触发 close 之间,间隔的时间本身就不长,再加上上一个ACK延时应答了,就可以把这俩数据合并了。合并相较于不合并来说,合并能够提升效率,因为一系列的封装分用都是有开销的。就好像我在哇在网上买了一件衣服,过了一会儿我还想买一件,如果商家还没打包发货,就可以把两件衣服放在同一个包裹里面。
合并场景是属于特殊情况的优化手段,但还是要把TCP的断开连接称为“四次挥手”。
四次挥手的意义,就是为了“释放空间”。建立连接需要保存信息,连接不用了,保存的信息自然就需要释放。