加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 教程 > 正文

TCP没那么难吧?这篇一定要看

发布时间:2018-09-03 17:23:21 所属栏目:教程 来源:余晟
导读:9月15日技术沙龙 | 如何将智能化和运维工作相结合,实现智能运维! 2013年,慕尼黑 如今相当多的程序员都是互联网程序员,按说,应该对互联网的基础协议相当清楚。可惜至少就我的面试经验来看,许多人这方面缺课太多,简单说说TCP/IP协议分层就已经难倒了不
副标题[/!--empirenews.page--] 9月15日技术沙龙 | 如何将智能化和运维工作相结合,实现智能运维!

TCP没那么难吧?这篇一定要看
2013年,慕尼黑

如今相当多的程序员都是“互联网程序员”,按说,应该对互联网的基础协议相当清楚。可惜至少就我的面试经验来看,许多人这方面缺课太多,简单说说TCP/IP协议分层就已经难倒了不少人。至于TCP/IP的“三次握手”,能说上来的人就相当少了,如果再问问“为什么是三次握手”,基本就没人能答上来了。一般的回答都是“这个太难”,或者“毕业太久,这个忘记了”。

如果临时抱佛脚,把TCP的三次握手背下来应付面试,确实能做到。但是要回答TCP为什么是三次握手,而不是两次或者四次握手,光靠背就不行了——不信你去网络上搜搜看,各种回答都有,众说纷纭,不少提问者一头雾水。

TCP相关的知识重要吗?我觉得挺重要的,这些年来无论互联网怎么变化,TCP协议本身都可以承载,仔细探究会发现它的设计的确够巧妙,有许多值得借鉴的设计思想。

那么TCP真的很难吗?为什么许多人背TCP的握手流程痛苦不堪,复述起来困难重重?我觉得,原因在于大家只把它当成“既存事实”, 就像上中学时候背历史政治那样对待。但TCP可不是毫无逻辑的胡说,一旦 你搞清了设计思想和逻辑,就会发现理解起来一点也不困难。所以,今天我来做个简单讲解。

首先说说“三次握手”这个译名,我确实觉得翻译有误(翻译出版过一百多万字技术资料,我自信还是有把握的)。我以前总记不住“三次握手”的过程,因为总觉得“握了三次手”,“握手”是双方共同往中间凑的过程,这明显和建连流程不符合。后来才发现,“三次握手”的说法大概有问题。

“三次握手”的原文是three-way handshake,three-way更合适的翻译恐怕是“三步”,所以整个名词的意思是“需要三个步骤才能建立握手的机制”。这么解释的好处是,“步”给人感觉更形象,就是“单方面迈一步”而已。实际上,RFC 793里说明了,握手过程也可以叫three-message handshake,通过三条消息来建立的握手。

那么,为什么要三步才能建立握手呢?我们可以暂时不理这个问题,想想如果我们自己来设计握手机制,应当怎么办。

我们都知道,TCP是可靠的通讯协议,其“可靠性”就在于,任何一方要向另一方发数据(SYN),都必须收到确认回应(ACK)。同时TCP也是双向的通讯协议,所以通讯的两方都可以主动发送消息。

这里要澄清的一点,对许多“互联网程序员”来说,TCP是掩盖在HTTP之下的,大家熟悉的HTTP,它的经典通讯模式是“一问一答”的,没有请求就没有应答。不过这只是HTTP的特性,不是TCP的特性。在TCP协议里,客户端和服务器都可以随时主动向对方发送数据——也正是因为如此,改用HTTP/2之后服务器可以主动推送信息给客户端,而不必改动TCP协议。

回到TCP,既然它是双向、可靠的通讯,可以想见,建立连接就必须确认双方到对方的通讯都是可靠的,所以大概需要四步,发送四次消息。

TCP没那么难吧?这篇一定要看

如果软件设计都这么简单,那就太好了。可惜,世界上没有那么简单的事情。仔细观察这幅图,我们会发现几个问题:

第一,网络通讯的成本是很高的,延迟往往无法预测,哪怕能少发送一次消息,也可以大大降低成本,提高效率。所以,建立连接的步骤上限应当是四步,下限是两步,越少越好。

第二,两轮SYN/ACK之间必须有关联,因为它们的功能相对独立,都是确认到对方的通讯可靠,却同属于一个“建立连接”的逻辑操作。如果两轮完全独立,那么如果两轮中间间隔了特别特别长的时间,根本不是一个正常的建立连接的操作,程序却无法识别,这显然是不行的。所以,第二轮SYN/ACK必须要能够和第一轮SYN/ACK关联起来。

再仔细看看,第二步和第三步都是从服务端给客户端发消息,所以是不是可以合并起来?这样起码可以节省了一次网络通讯。

TCP没那么难吧?这篇一定要看

像上面这样直接在第二步把ACK和SYN合并起来,问题就解决了?

按照之前的分析,节省消息发送次数只是考虑之一,还需要考虑的是,第二轮SYN/ACK必须和第一轮SYN/ACK挂钩。

TCP没那么难吧?这篇一定要看

上面是TCP的数据报,包含了许多的控制位,用来标识连接的状态。其中最常见的是SYN、ACK、FIN:SYN表示synchronize,在建立连接时使用;ACK表示acknowledge,表示“确认”收到了消息;FIN表示finish,在断开连接时使用。

还要注意的两个东西是SEQ NO和ACK NO。SEQ NO即Sequence Number,服务端和客户端都会维护自己的SEQ NO,表示“已经发送了多少数据”,单位是字节;ACK NO即Acknowledge Number,用来回复确认,对应SEQ NO的数据已经收到。单独说起来,这些概念都容易理解,只是注意不要混淆控制位的ACK和ACK NO——ACK是布尔值用来标识数据报的类型,ACK NO是数值用来确认已经收到的数据。

基于上面的知识我们可以知道,在建立连接之初,数据报中的控制位SYN应当设定为1,表示“新建连接”;同时应当包含SEQ NO。此时的SEQ NO有个专门的名字叫ISN,也就是Initial Sequence Number(要注意,ISN只是用来称呼这个特殊SEQ NO,并不存在专门的ISN字段)。

在服务端收到第一个SYN消息的时候,它当然需要发送ACK响应,但它如何确认其中的SEQ NO“就是”新建连接的ISN,而不是来自姗姗来迟的某个古老连接呢?所以必须向客户端确认。恰恰因为第二步是ACK,SYN“合二为一”的独特响应,所以收到这个消息时,客户端就知道,既需要响应其中的SYN,也需要核实其中的ACK(如果你仔细读过RFC793就会知道,其中专门有一段提到了: A three way handshake is necessary because…… )

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读