写点什么

TCP:当初取代 NCP,如今害怕被取代

作者:C++后台开发
  • 2022-10-18
    湖南
  • 本文字数:4368 字

    阅读完需:约 1 分钟

TCP:当初取代NCP,如今害怕被取代

我叫 TCP(Transmission Control Protocol)也叫传输控制协议。不觉回忆 1983 年,亲手将 NCP 协议淘汰,取而代之的是我,成了火遍大江南北的网络红人之一。

现如今,我感受到前所未有的恐惧,因为我一生的敌人 UDP 正在赶超我,甚至将我取而代之。

我的生平

我在 1974 年被我的父亲罗伯特·卡恩和温特·瑟夫设计出来,和我一同出生的也是如今的网络红人 IP,我们是一对亲密无间的组合——TCP/IP,我在网络七层模型里的 4 层——传输层,而 IP 兄弟是负责网络层。

我的作用就是负责传输数据,并代替 NCP 协议的工作,因为它不能跨系统通讯,怎么说呢,就是如果大家用了 Windos 操作系统,就没法和 MacOs 操作系统进行通讯,这非常不利于互联网的发展,我很抱歉 NCP 一时被抛弃,但是我们依然坚信“物竞天择,适者生存”的道理。

起初出生时,我们并没有大家想象的那么容易。刚出生时的我是非常简陋的,我的 IP 兄弟负责每个机器分配一个 IP 地址标识。IP 兄弟像是为我铺好了康庄大道,而我只需要将数据包运输到目的地。而我们也比较争气,我的父亲卡恩和瑟夫为我做了一个实验,将一个数据包从一端发出,经过 10 万千米的旅程后到达服务端。这个传输过程,数据包没有丢失一个字节!

但是,我们的命运和其他伙伴一样,新技术或新标准起初总是会受到强烈的抵制。特别是标准化组织 ISO 推出了著名的 ISO 七层模型,那时我又被强烈的鄙视了一番。

不得不说,父爱是伟大的,他们经过 4 年时间的不断对我们改进,为我和 IP 兄弟完成了基础框架的搭建。

尽管阻碍重重,我的父亲卡恩和瑟夫进行了长期的斗争。

终于,在 1983 年被美国国防部高级研究计划局决定淘汰 NCP 协议,我和 IP 兄弟取而代之。

这个过程,整整过去了 10 年的时间。我和我的亲兄弟 IP 终于站稳了脚跟,分别负责七层模型里的传输层,网络层。

现如今,接触计算机的朋友们对我一定不陌生。我在网络中扮演着重要角色,你们发送的信息基本上都是我在负责的,每时每刻都在处理成千上万用户的信息,还要安全且无误的传输到指定的地方。

这时候你可能反应过来了,你用手机,电脑等设备对你恋人或者亲人说的话,语音,视频都是我负责帮你们成功抵达,而且是准确无误,因为至今正常情况下我没有收到你们错误信息的抱怨。

我可以自信地说是印度洋和太平洋之间重要枢纽——马六甲海峡。

当然我的亲兄弟 IP 也是功不可没,它为我连通了各个设备搭建好了桥梁,那么我根据 IP 我就能找到准确的人给他发送。而且还划分了网段,这样你在浙江给在北京的爱人发信息,那我一定是往北走,而不是往西,或者往南走。

你可能会好奇,我是怎么做到每时每刻处理成千上万的信息安全且无误地传输到目的地。这得归因于我父亲对我的设计了,他们致力于让我成为一个安全且靠谱的“运输卡车”。

三次握手机制

第一次握手,做了什么?

这第一个安全的设计,就是连接机制,为了确保能够建立正确的连接,大部分情况下我需要三次连接才能建立安全可靠的传输通道。也就是你们常说的“三次握手”连接。

首先客户端要和服务端建立 TCP 连接,也就是建立通讯管道。会先发一个 SYN 报文,这是一个请求同步连接的报文,发送之后此时的客户端会进入到 SYN-SENT 状态。

如果客户端迟迟收不到服务端的 SYN-ACK(同步应答)报文,就会触发超时重传机制,重新把刚才的 SYN 报文重新发送,而且重传的 SYN 报文的序列号都是一样的。

你可能会好奇客户端没有收到应答之后,多久才会触发重传且需要重传几遍才肯罢手。

不同版本的操作系统可能超时时间不同,有的 1 秒的,也有 3 秒的,这个超时时间是写死在内核里的,如果想要更改则需要重新编译内核,比较麻烦。

在 Linux 里,客户端的 SYN 报文最大重传次数由 tcp_syn_retries 内核参数控制,这个参数是可以自定义的,默认值一般是 5,所以这个可以是由操作系统来设定的。

假如我们设置初始超时重传 1 秒,最大重传次数为 5 次。那么客户端第一次超时重传是在 1 秒,第二次超时重传是在 2 秒,第三次超时重传是在 4 秒 ,第四次超时重传是在 8 秒 , 第五次超时重传是在 16 秒。我们可以看到规律,每次超时时间是上一次的 2 倍。

当到了第五次重传时,将继续等待 32 秒之后服务端还是没有响应 ACK,客户端将不再发送 SYN 包,然后断开 TCP 连接。

​▲图/ 第一次握手超时重传机制

第二次握手,做了什么?

第二次握手,也就是客户端发送的 SYN 报文,如果服务端收到了就会返回一个 SYN-ACK 报文给客户端,并且服务端进入 SYN_RCVD(同步已接收)状态。

此时的 SYN-ACK 报文做了两件事,一件是对第一次握手时做个回应确认报文已经收到。另一个是服务器既然收到了便会发起建立 TCP 通信管道的连接的报文,这个地方是一个发送请求时间,如果没有得到 ACK 回应则会触发超时重传机制。

C/C++Linux服务器开发高级架构师/C++后台开发架构师​免费学习地址
另外还整理一些 C++后台开发架构师 相关学习资料,面试题,教学视频,以及学习路线图,免费分享有需要的可以自行添加:Q群:720209036 点击加入~ 群文件共享

​此时,如果服务端的 SYN_ACK 报文发送了之后,如果丢失或者某种原因导致客户端没有收到,只要客户端没有接收到就会触发超时重传机制(会有计时器,超过时间没接收到就重传),重传 SYN 报文。

当然为了确保稳定,不仅客户端会有重传机制,服务器也会有超时重传机制,重发 SYN-ACK 报文。 在 Linux 下,SYN-ACK 报文的最大重传次数由 tcp_synack_retries 内核参数决定,默认值是 5。

​▲图/ 第二次握手超时重传机制

第三次握手,做了什么?

这个时候,客户端收到服务端的 ACK 应答报文并发起了 TCP 建立连接请求,此时客户端收到并对 TCP 建立连接得请求发送一个 ACK 应答报文,并且客户端进入 ESTABLISH 的建立连接状态。

我们可以看到此时的第三次握手是基于第二次握手服务端发来的 SYN 的确认报文,如果客户端没有收到,那么服务端此时会触发超时重传机制,进行重发相同的 ACK 报文。

​▲图/ 第三次握手超时重传机制

由此,我们也可以总结出结论,ACK 应答报文并不会有重传机制,当 ACK 丢失了,由对方发来的 SYN 报文进行重传。

以上就是我的建立连接机制了。你们可能会看起来比较麻烦,特别是当今世界如果聊天出现了三次握手的情况,你们一定是不耐烦的。然而,我这是牺牲了一定的速度来确保安全以及稳定的作用,我想人们更多情况下都是求安全且稳定的。

四次挥手机制

我虽然在一定程度上具有传统且保守的态度,但是我一定是力争求稳,且有始有终,是你们靠谱的伙伴。所以,在传输结束时,我也有一套安全稳定的断联机制。就是你们俗称的“四次挥手”。

第一次挥手,做了什么?

第一次挥手,当客户端所有的消息都发送完之后,会主动调用 close 函数,然后向服务器发送 FIN(完成)报文,试图和服务器断开连接,并且状态进入到 FIN_WAIT_1 状态。

客户端不管何种情况,只要没有收到 ACK 报文,就会触发超时重传机制,重传 FIN 报文,重传次数也是由操作系统 tcp_orphan_retries 参数设置。

​▲图/ 第一次挥手超时重传机制

超时重传到达 tcp_orphan_retries 的次数之后,就不再发送 FIN 报文,则会等待上一段时间的 2 倍之后还是没有收到,则直接进入 close 状态。

第二次挥手,做了什么?

第二次挥手,服务端收到客户端的第一次挥手之后会回传一个 ACK 确认报文,此时服务端的状态进入到 CLOSE_AWAIT 状态。

由于 ACK 报文是没有重传机制的,所以一旦服务端没有把 ACK 回传给客户端且接收到,则由客户端发送方来触发超时重传机制。这也是一问一答式的,必须有问有答才算一回合结束。

​▲图/ 第二次挥手超时重传机制

客户端收到 ACK 报文,则状态由 FIN_WAIT_1 变为 FIN_WAIT_2 的状态。这个状态需要等待服务端发送第三次挥手,也就是服务端的 FIN 报文。

这里,客户端收到 ACK 进入到 FIN_WAIT_2 状态之后,调用 close 关闭函数,之后便无法再发送和接收数据,所以这个 FIN_WAIT_2 状态也不会持续很长,而 tcp_fin_timeout 控制了这个状态下连接的持续时长,默认值是 60 秒。

​▲图/ close 函数关闭机制

意味着如果在 60 秒后还没有收到 FIN 报文,客户端的连接就会直接关闭。

但是如果客户端(主动方)关闭使用 shutdown 函数代替 close 函数关闭连接时,指定了只关闭发送方,而接收方并没有关闭,那么主动关闭方还是可以接收数据的。

服务端(接收方)还在处于接收状态就无法发送 FIN 报文,那么客户端(主动方)就会一直处于 FIN_WAIT_2 状态,你可能会想 tcp_fin_timeout 这个时间倒计时可以主动关闭状态。很遗憾,tcp_fin_timeout 这个参数只对 close 函数有用,对 shutdown 函数无效,并会处于一直等待中,没有杀死这个线程甚至可能死等中。这是一个不到万不得已的下策。

​▲图/ shutdown 函数关闭机制

第三次挥手,做了什么?

到了这里,进入到第三次挥手。在上一轮服务端进入 CLOSE_WAIT 状态后,进程主动调用 close 函数进入到内核,内核会发送一个 FIN 报文,同时进入 LAST_ACK 状态,等待客户端返回 ACK 来确认连接关闭。\

​▲图/ 第三次挥手超时重传机制

这里,如果迟迟收不到客户端返回的 ACK 报文,则依然会触发重传机制,重发次数仍然由 tcp_orphan_retries 参数控制。

第四次挥手,做了什么?

服务端发送了 FIN 报文之后,就进入到第四次挥手了。当客户端收到服务端的第三次挥手的 FIN 报文之后,就会回传一个 ACK 报文,也就是第四次挥手,并且进入到 TIME_WAIT 状态。

TIME_WAIT 状态根据操作系统的不同,一般 Linux 系统是持续 2MSL(2 倍的最大生存时间)进入关闭状态。

​▲图/ 第四次挥手超时重传机制

服务端若没有收到客户端发来的 ACK 报文,则依然处于 LAST_ACK 状态。超时未接收到则客户端会触发超时重传 FIN 报文,重发次数仍然由前面介绍过的 tcp_orphan_retries 参数控制。

时代的眼泪

你看,这是我有始有终的机制,对于我来说,每一步都不是多余,都是为了双方能够建立安全稳定的通道,不会在错重复杂的通讯管道中将数据错误的传达。

当然,这些是我在连接和断开方向上的主要特点。我的主要功能不仅这些, 重传、滑动窗口、流量控制、拥塞控制都是我的一套完整的高可用体系。

在我和应用层 HTTP 组合已经有四十年左右,在此期间我可以是撑起整个互联网的元老之一,毫不夸张的自诩为互联网的血脉。但是也难挡时代带来的风霜,我有一个死对手 UDP,这个将是我永远过不去的坎,以前我从没觉得它能够赶超我甚至替代我,它的好处就是快,靠不靠谱我不说。

但是随着时代的发展,人们对于速度的要求越来越高,人们不断地改良网络模型,我的兄弟也在升级,已经有了 IPv6,而与我患难与共的 HTTP,则是不断的从 1.0 优化到了 3.0,这个版本的出现彻底的让我感到 emo,因为 http3.0 版本已经使用我的死对头来替换了我,他们将 UDP 的速度发挥起来,并且对于安全连接和数据校验相关做了很好的控制。

参考资料

​推荐一个零声教育 C/C++后台开发的免费公开课程,个人觉得老师讲得不错,分享给大家:C/C++后台开发高级架构师,内容包括Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习

原文地址:TCP:当初取代NCP,如今害怕被取代 - 掘金

用户头像

C/C++后台开发技术交流qun:720209036 2022-05-06 加入

还未添加个人简介

评论

发布
暂无评论
TCP:当初取代NCP,如今害怕被取代_后台开发_C++后台开发_InfoQ写作社区