文章目录
- 连接管理机制
- 1. 建立连接(三次握手)
- 2. 断开连接(四次挥手)
TCP 的工作机制
确认应答机制
超时重传机制
连接管理机制
比如 主机A 的空间存储了 主机B 的 ip 和 端口,主机B 的空间存储了 主机A 的 ip 和 端口。
当这两部分信息都被维护好了之后,此时连接就有了。
此时也把保存这部分信息的这个空间(数据结构)也称为 连接。
这就好比两个人结婚,结婚证上面会有彼此的另一半是谁,有了结婚证说明这两个人才是正式结为了夫妻,
此时才是成功建立了连接。
如果要断开连接,A 和 B 把自己存储的信息(数据结构)删除了,此时连接就断开了。
管理就是描述了连接如何创建,如何断开。
1. 建立连接(三次握手)
建立连接就是通信双方各自要记录对方的信息,彼此之间要相互认同。
举个例子来说明什么是建立连接。
首先,张三向小红表白,接下来小红接受了张三的表白。此时双方就有了一个认同:小红是张三那个唯一的人。
但是要想成为男女朋友,就需要双方互为唯一,所以此时小红也向张三表白。
这个时候,又建立了一次认同,张三这边知道了,自己是小红唯一的人,而小红这边也知道了张三是她唯一的人。
这个时候才是正真的建立了男女朋友的关系,相当于是连接建立完毕。
此处就把这个过程中的每一次通信都称为一次 “握手”。
如果仔细观察就会发现上面的交互一共是 4 次,那为什么不叫做 四次握手呢?
因为有两次交互是可以合二为一的。
小红在接收张三表白的同时向张三表白,这就节省了一次数据的传输。
通信双方各自要向对方发起一个 “建立连接” 的请求,同时再各自向对方回应一个 ACK,所以这里是有四次信息交互的。
所谓的三次握手,本质上是 四次握手。这是由于中间两次交互是可以合并成一次交互的,因此就构成了三次握手。
这里将两次交互合二为一可以降低成本,好比在一家店铺买了三件商品,商家会打包成一个包裹运过来。
因为这样只需要付一份的运费,而不是分成三个包裹,付三份运费。
为什么不能是两次握手?
如果少了最后一次握手,张三知道了自己是小红的唯一,也知道了小红是自己的唯一。
但是小红这边不知道自己是张三的唯一,也不知道张三是不是她的唯一。
此时从小红的视角张三有可能同时在和多个女朋友交往,相当于是没有建立男女朋友的连接。
三次握手还有另外一个重要的作用,验证通信双方各自发送能力和接收能力是否正常。
三次握手也在一定程度上保证了 TCP 传输的可靠性,但是起到的不是关键作用,而是辅助作用。
举个例子来说明。
比如现在李四和张三开黑打游戏,需要连麦,但是在游戏开始之前需要通过三次握手来进行测试验证麦克风和听筒有没有问题。
第一次交互:
1、当李四听到了 “hello !收到请回答” 后,李四就知道了张三的麦克风是好的,李四自身的耳机也是好的。
但是还不知道李四的麦克风是否是好的,也不知道张三的耳机是否是好的。
第二次交互:
2、当张三听到 “收到收到” 后,张三就知道了自己的耳机和李四的麦克风是好的。
同时由于之前是约定好,李四听到张三的 “收到请回答” 后才回复 “收到收到”,所以此时张三的麦克风和李四的耳机是好的。
张三这边已经知道了开麦交流的能力都OK了,但是李四那边的还不清楚,所以需要 第三次交互 同步一下情报。
第三次交互:
1、此时李四听到了 “OKOK” 意味着此时刚才李四发的 “收到收到” 已经被张三收到了。
意味着李四的麦克风和张三的耳机都是好的。
此时双方都知道了,彼此的麦克风和耳机都是好的。
三次握手的意义
1、让通信双方各自建立对方的 “认同”。
2、验证通信双方各自的发送能力和接收能力是否OK。
3、在握手的过程中,双方来协商一些重要的参数。
TCP 通信过程中有些数据通信双方要相互同步,此时就需要有这样的交互过程。
恰好可以利用三次握手的机会来完成数据的同步。
客户端主动给服务器发起的建立连接请求,称为 SYN,这个是 同步报文段。
客户端是主动的一方,服务器是被动的一方,一定是客户端先向服务器发起 “建立连接请求”。
客户端服务器这个身份概念只是按照主不主动来进行区分的。
同一个程序在不同的场景下可能是作为服务器也可能是作为客户端。
三次握手中的TCP 的状态
圈出的描述了TCP的状态,TCP 不同的状态就体现了当前 TCP 在干什么。
建立连接阶段主要认识两个状态:
1、LISTEN 服务器的状态。
表示了服务器已经准备就绪,随时可以有客户端来建立连接了。相当于手机开机,信号良好随时可以有人来打电话。
2、ESTABLISHED 客户端和服务器都有。
连接建立完成,接下来就可以正常通信了,相当于电话拨过去,对方接通了。
圈出的描述了 TCP 和 socket api 之间的关系,此处的 socket api 是系统原生 api (C语言版本)
这个和 java 版本的已经有了一定的差距,因此这里不做关注。
2. 断开连接(四次挥手)
四次挥手和三次握手非常类似,都是通信双方各自向对方发起一个断开连接的请求,再各自给对方一个回应。
经过双方确认分手后,两个人确定断开了连接变成了陌生人。
需要注意的是断开连接中间两条交互,在通常下是不可以合而为一的。
如果两个数据的发送时间相同才能合并,如果是不同的时机,就无法合并!!!
为什么不能合二为一
举个例子。比如说在网上买快递,如果是在一个店铺同时下了多个订单,那么店家会发一个快递,承担一份运费。
如果是一周下一个订单,分三次下完,那么此时店家就会发三个快递,承担三份快递。
主要是因为下订单的时间是完全不同的。
三次握手中的两次能够合并是因为这两个是同一时机的。
具体来说,三次握手这三次交互过程,是纯内核中完成的。(应用程序感受不到,也无法干预)
服务器的系统内核收到 SYN 之后,就会立即发送 ACK 也会立即发送 SYN。
FIN 的发起不是由内核控制的,而是由应用程序调用 socket 的 close 方法(或者进程退出)才会触发 FIN。
ACK 则是由内核控制的,是收到了 FIN 之后立即返回 ACK,服务器的应用程序执行到对应的 close 方法才会触发 FIN。
这两者之间就回隔了一个时间差,这个时间是长还是短,取决于代码是在怎么实现的。
四次挥手中的TCP 的状态
四次挥手涉及到了两个重要的 TCP 状态:
1、CLOSE_WAIT 出现在被动发起断开连接的的一方。等待关闭 (等待调用 close 方法关闭 socket)
建立连接一定是客户端主动发起请求,断开连接可能是客户端主动发起也可能是服务器主动发起。
2、TIME_WAIT 出现在主动发起断开连接的一方。
假如是客户端主动断开连接,当客户端进入 TIME_WAIT 状态的时候,相当于四次挥手已经挥完了。
此时,这里的 TIME_WAIT 要保持当前的 TCP 状态不要立即就释放。
为什么 TIME_WAIT 会保留一会连接不立即释放???
此时最后一个 ACK 刚刚发送出去还没到呢!如果这个最后一个 ACK 丢包了呢?
因此,TIME_WAIT 会等一会,如果超出了等待的时间也没有收到重传的 FIN,此时就认为最后一个 ACK 没丢包,
于是就彻底的释放连接了。
在三次握手和四次挥手的过程中,同样是存在重传的。
如果是最后一个 ACK 丢包了,站在服务器的视角来看,服务器是不知道是因为 ACK 丢了,还是自己发的 FIN 丢了。
所以统一视为 FIN 丢了,统一进行重传操作。
既然服务器可能要重传 FIN ,客户端就需要能够针对这个重传的 FIN 进行 ACK 响应。
很明显,如果刚才彻底把连接释放了,这样的 ACK 就无法进行了。因此使用 TIME_WAIT 状态保留一定的时间,就是为了能够处理最后一个 ACK 丢包的情况,能够在收到重传的 FIN 之后进行 ACK 响应。
TIME_WAIT 保存的具体时长
约定了一个时间,叫做 2MSL 指的是,互联网上两个结点之间数据传输消耗的最大时间。
如果 A 经历了 2MSL 这个时间还没收到重传的 FIN ,就认为上个 ACK 就正常到达了(认为对方没有重传 FIN 了)
MSL 这个值通常情况下是 60s,但是传输数据的实际时长完全是有可能会超过 60s 的。
如果把 MSL 定义为 1h,传输数据的实际时长也有可能是比 1h 多的。
无论如何定义 MSL 都无法理论上排出这样的特殊情况,因此 MSL 其实相当于是一个经验值。
按照一般的经验来说,绝大部分(99.99%)数据传输的时间都不会超过 MSL。
小结:
TCP 作为一个有连接的协议,就需要建立连接和断开连接。
其中建立连接的过程是三次握手,断开连接的过程是四次挥手。
三次握手的意义:
1、让通信双方各自建立对方的 “认同”。
2、验证通信双方各自的发送能力和接收能力是否OK。
3、在握手的过程中,双方来协商一些重要的参数。