如果有人问我推荐技术类书籍,我个人首选一定是【TCP/IP 详解】原版。这种大部头的经典之作里所包含的知识,说是浩如烟海也不为过,每次重新翻起总会有一些新的体悟和收益。经典的好处在于,它描述的一般是通用的计算机问题,可以帮助读者形成通用的计算机思维,而不局限于某一领域或某一场景,常看常新。
当然这本书的厚度也到了让人望而生畏的程度,如果着急短时间内啃完,多半会由于无法完成目标的沮丧半途而废。我在前面的文章中也提到过,获取知识的时候容易陷入「越看越饿」的焦虑感,这种情形下应该放慢节奏,指定长期的阅读计划,放眼于较长时间跨度的收益。书和文章并不是越多越好,看了多少,能消化多少,是个人的事情,没有比较的意义。知识营养,点滴皆是财富,积跬步而至千里方为正途。
一般来说,看一手技术书籍比看技术文章更有意义。但好的技术文章,如果能做到高屋建瓴,提纲挈领,对于初学者入门也是具备价值的。直接啃英文原版,没有交流和正向反馈,最后能否读完十分考验读者的意志力。
我打算写一个 TCP/IP 的系列文章,目的在于以通俗易懂的语言和比喻,让读者能预先形成一个初步的知识大纲,之后再能有针对性的逐个知识模块去攻破。即使最后无法通读【TCP/IP 详解】全本,也能对网络协议栈形成大致完整的框架理解,以后在项目中遇到问题,至少知道如何下手,从哪个方向去深入突破。感兴趣的读者在阅读这个系列文章之时,最好能同时翻阅下【TCP/IP 详解】,疗效更佳。
打算写这个系列的另一个原因,是我在平时阅读英文书籍的过程中,深感中西方思维方式的差别,会让一些原本简单清晰的概念模型变得晦涩费解,一些关键点如果无法攻克,会阻碍进一步学习的兴趣。另外,我会以 iOS 程序员的视角,尽量结合一些实际应用中的具体场景来讲解,不至于太过枯燥,感觉不到学习的意义所在。
这个系列会在后续的时间里,夹杂着其他文章一起写,可能会耗时较长,又或者会一直写下去。我现在感觉公众号越来越像「读者群」,留下来坚持读文章的多半和我「品性相投」,不论我写技术还是写心得都会坚持阅读。于我,写文章是一件乐事,于读者,看文章多少有些收获。一场双方都觉得愉快的聊天岂不是妙事一件。
接下来进入正题。
TCP/IP 初印象
当我们聊 TCP/IP 的时候,一般是在说整个网络协议栈。也就是大家熟知的 OSI 七层模型。我们先抛开七层协议和三次握手这些生硬的知识点,简单聊聊网络协议栈到底是做什么的。
网络协议要解决的问题很简单,打个比方,就是让身处不同地方的两个人,能完成聊天通讯。无论我们谈及哪一方面的网络知识点,最后都不会脱离这个最基本的场景模型。
首先我们需要分清楚流和包的概念,这也是不少初学者容易混淆的问题。当我们以 iPhone 上的 App 客户端,向我们的 Server 发数据的时候,我们可以用 Charles、MITMProxy 这类工具抓包,但我们同时也知道 TCP 是基于流的协议,这二者的区别和联系在哪呢?
0 和 1 是计算机世界的基础粒子,大量的 0 和 1 组合在一起就形成了一个流(Stream),客户端向服务器发送数据的时候,说白了就是一堆 0 和 1 的组合。一次完整的 http 会话是建立在一个 TCP 连接之上,这个 TCP 连接的生命周期内所有发送的数据最后可以看做是一个流。而在这个流里,我们可以按照某种规则把它切割成一个个的包(packet)。比如 TCP 三次握手里就包含了 SYN,SYN+ACK,ACK 三个包,而这三个包,不过是整个 TCP Stream 最开始的部分数据而已。
所以简单来说,一个 TCP 连接里,是既有流的概念,又有包的存在,有些问题场景下会谈论流,另一些则会说起包,端看具体的场景如何。
在开始学习 TCP/IP 之前,最好能在脑中形成一幅 Gif 动态图像,客户端和服务器之间有两根管道,一根上行(从客户端到服务器),一根下行(从服务器到客户端),管道里流动着无数的 0 和 1,有时候管道里是满的,有时候管道里则空空如也,每次发送数据,都会有大量的 0 和 1 从一端涌向另一端。
有了这个基本的抽象理解,就可以进一步填补一些图像细节。
比如 0 和 1 是以什么形式流动的呢?这个在不同时代里,所用的物理硬件不同,原理自然也不同,现在大多用的是光纤,光纤里的 0 和 1 流动可以用下图表示:
物理层离应用层较远,深入学习的意义无法立竿见影,遇到实在费解的,可以先跳跃式的阅读,但有些基础的细节还是需要明白的。比如,我们知道光速大致是 300000 km/s ,而光在光纤中的物理传播速度大概是光速的 ⅔,这个知识点可以帮助我们大概估算一个 TCP 连接中的 RTT 值。RTT 即 Round Trip Time,表示一个包从发送方发出,到收到接收方的反馈,一共耗时多少。RTT 值反应的网络延时的状况,在很多场景下分析问题都有意义,比如 TCP 重发机制中的 RTO 就跟 RTT 有关,后面的文章我们会细说。一些知识点往往是环环相扣的,跳过的内容过多,后面学习起来会更费解。
延迟
再说下延迟的概念,延迟和带宽是我们谈及网络状况的两个重要指标。延迟看上去很好理解,延迟对应的英文术语是 Latency,不少人会觉得延迟主要跟通讯双方的物理距离相关,距离越远,自然延迟越高。其实网络延迟严格来说,是由两部分组成的,其一是 Transmission Delay,另一个是 Propagation Delay。这里出现了一个新单词 Delay,Delay 和 Lantency 的含义在中文语境里很难区分,但在英文语境下,二者的使用却是有明显的场景差别的,这也是为什么读英文原版很重要,可以让被描述的问题细节更清晰。
先说 Transmission Delay。计算机世界里的 0 和 1, 最后要能在光纤中传输,需要在 Physical Layer 将数字信号转化为物理信号,这个转化也是存在速度瓶颈的,我们用 Rate (bits/seconds) 来描述这个转化的速度,Rate 表示每一秒钟里,硬件设备能将多少 bits 转化为光信号放入光纤中,那么 Transmission Delay 就可以用如下公式表示:
Transmission Delay = M / Rate
M 表示有多少 bits。
Transmission Delay 描述的是硬件转化信号的延迟,这一步里信号还没有正式进入光纤中传播,这种延迟和通讯双方的物理距离是没有关系的。
再来是 Propagation Delay。这才是大部分人所理解的传播延迟,和距离直接相关。也可以用如下公式表示:
Propagation Delay = L / S
L 表示两地的物理距离,S 表示光纤中的传播速度,即为 ⅔ 光速。
最后我们才是所说的网络延迟:
Latency = Transmission Delay + Propagation Delay
像这种知识细节,如果不去看书,是很难形成准确认知的,这种细节丰满的认知不是快餐式技术文章可得,需要静下心来,花时间慢慢啃,一旦形成之后,就牢固的沉淀在记忆里,这样才算真正掌握了这方面的知识。
管道容量
再说个有意思的知识点。我们经常将网络通道比作自来水管道,这种比喻其实很贴切,网络管道和自来水管道一样,也是存在容量限制的。也就是说,光在光纤中传播的时候,会像自来水一样,填满整个光纤,光纤也存在管道容量的限制。有时候,光纤管道会变得很拥挤,一旦拥挤起来,有些包就要排队等待,延迟就会增加,丢包率也会随之上升,整个网络状况就会变差,这也是为什么 TCP 要做 Flow Control(流控),Flow Control 也是个很经典且有趣的问题,后面会专门写文章介绍。
网络管道的容量也是可以通过上面提到的元素,用公式计算的:
BD = Rate * Propagation Delay
大家可以思考下这个公式为什么会是这样。
好啦,序篇就到这,后面的文章里,我会逐个讲解一些关键且重要的知识点。一同进步吧!