This commit is contained in:
louzefeng
2024-07-11 05:50:32 +00:00
parent bf99793fd0
commit d3828a7aee
6071 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
我用将近半年的时间在“极客时间”写了一个专栏“趣谈网络协议”。对于我自己来讲,这真的是个非常特殊而又难忘的经历。
很多人都很好奇,这个专栏究竟是怎么一步步创作出来的,每一篇文章是怎么写出来的?自己录音频又是什么样的感受?写完整个专栏之后,我终于有时间回顾、整理一下这半年的所感所想。对我来说,这是一次难得的体验,也是一次与“极客时间”的深度沟通。
## 专栏是写给谁的?
和极客时间的编辑谈妥主题之后他们首先要求我基于约定的主题写一个36节至50节的大纲之后会以每周三篇的频率文字加音频的方式发布。每篇文章的体量要求在3000字左右录成音频大约就是10分钟。
我本来觉得写这么一个专栏根本就不是个事儿。毕竟咱也是在IT圈摸爬滚打了许多年的“老司机”干货积累得也不少。只要是熟悉的领域不用准备聊个把小时都没啥问题。况且我原来还写过书、写过博客、写过公众号。所以我对自己文字方面的能力很有自信。
至于语言方面咱常年出入各大技术论坛什么场子没趟过。一个两天的线下培训咱都能扛过来。每篇10分钟总共36篇那不才是6个小时嘛肯定没问题。
但是,写了之后我发现,**自己会是一回事儿,能讲给别人是另一回事儿**,而能讲给“看不见的陌生人”听,是这世上最难的事儿。
我知道,很多技术人都有这样一个“毛病”,就是觉得掌握技术本身是最重要的,其他什么产品、市场、销售,都没技术含量。这种思维导致很多技术比较牛的人会以自我为中心,仅站在自己的角度思考问题。所以,**常常是自己讲得很爽,完全不管听的人是不是真的接受了**。写专栏的时候,这绝对是个大忌。
除此之外,这种思维对职业发展的影响也是很大的。单打独斗,一个人搞定一个软件的时代已经过去了。学会和别人合作,才是现代社会的生存法则,而良好的合作源于沟通。
但沟通不易,高质量的沟通更难。面对的人越多,沟通的难度就越大。因为每个人的背景、知识、基础都不同,想听的内容肯定更是千差万别。况且不是每个人都能准确地表达出自己的需求,加之需求的表达、转述都会因表达方式和传递媒介而发生变形,这样一来,接收信息的一方自然很难把握真实的需求。
写专栏的时候,“极客时间”的编辑不断地告诉我,我的受众只有一个人,就是“你”。我心想,这个简单啊,因为面对的人最少嘛!可是,事实上证明,我又“错”了。
这个抽象的“你”看起来只有一个其实却是看不到、摸不着的许许多多的人。所以这个其实是最难的。协议专栏上线10天就有10000多人订阅而订阅专栏的用户里只有少数人会留言。所以对于很多读者的真实情况我都无从得知你可能每天都听但是没有留言的习惯也可能买了之后觉得我讲得不好骂一句“这钱白花了”然后再也不听。
所以,**如何把控内容,写给广大未知受众,是我写这个专栏面临的最大挑战**。而这里面,文章的深度、广度,音频的语调、语气,每一个细节都非常重要。
## 专栏文章是怎么写的?
经过大纲和前几篇文稿的打磨,我对“极客时间”和专栏创作也有了更深的了解。我私下和很多人交流过一个问题,那就是,咱们平时聊一个话题的时候,有很多话可以说。但是真正去写一篇文章的时候,好像又没有什么可讲的,尤其是那些看起来很基础的内容。
我在写专栏的过程中,仔细思考过这样一个问题:很多人对某一领域或者行业研究得很深入,也有自己长期的实践,但是**有多少人可以<strong><strong>从感性认识上升到理性**</strong>认知**<strong>的**</strong>高度呢?</strong>
现在技术变化这么快,我们每个人的精力都是有限的,不少人学习新知识的方式就是看看书,看看博客、技术文章,或者听同事讲一下,了解个大概就觉得可以直接上手去做了。我也是这样的。可是一旦到写专栏的时候,**基础掌握不扎实的问题一下子全都“暴露”出来了。**
落到文字上的东西一定要是严谨的。所以在写到很多细节的时候我查了大量的资料找到权威的书籍、官方文档、RFC里面的具体描述有时候我甚至要做个实验或者打开代码再看一下才放心下笔。
尽管我对自己写文章有很多“完美倾向”的要求,但是这其实依旧是站在我自己的角度去看的。读者究竟想要看什么内容呢?
太深入了,看不懂;太浅显了,也不行。太长了,负担太重;太短了,没有干货;同时,每篇文字还要自成一体,所有文章要是一个完整的知识体系。我发现,原来我不仅是对知识的了解没那么全面、具体,对用户阅读和倾听场景也没有过多的考虑。
除了写文字,专栏还要录音频,所以为了方便“听”,文章内不能放大量代码、实验。如果很多人在通勤路上听,而我把一张图片讲得天花乱坠,听的人却根本看不到,那肯定是不行的,所以写文章的时候,我还要把故事性、画面感都考虑进去,尽量详尽而不啰嗦。
把这些限制条件加起来之后,我发现,写专栏这件事儿,真的太不容易了。每篇文章看起来内容不多,但是都是费了很多心思的,这也是为什么很多老师说,写完专栏就像是过了火焰山。
## 专栏音频是怎么录的?
说完写文章,我来说说录音频。我平时听播音员说话,感觉非常轻松,所以当时我毫不犹豫地就说,“我要自己录”。但是在录开篇词的时候,我就觉得这完全不是我想的那么回事啊!
专栏的文章在录音的时候一定会有个“音频稿”,我一开始很不理解,我对着发布的稿件直接讲就好了啊,为什么还要特意准备一个供录音频的稿件啊?
我在没有音频稿的情况下,自己试着“发挥”了几次,结果,我发现我的嘴会“吃”字,会反复讲一个内容而且表达不清,但是自己却经常毫无察觉,还会自己讲着讲着就收不住等等。
咱们平时说话的时候,会有很多口头语和重复的词语。面对面交流的时候,我们为什么没有注意这个问题呢?因为我们会更注重对方的表情、手势,但是一旦录成音频,这些“啰嗦”的地方就特别明显。
而有了音频稿之后,整个过程就严谨很多。如果哪句话说错了,看着稿件再说一遍就好了。而且,你会发现录音的时间大大缩短了,原来需要用十分钟,现在五分钟就可以很精炼地讲出来了。
有了稿子,那我是不是对着念就好了?这不是很容易吗?不,我又遇到了新的难题。
录音频的时候,我常常一个人关在密闭的房间里,对着显示器“读”,这和公共演讲肯定是不一样的。加上因为有写好的音频稿,我常常感觉束手束脚,找不到演讲那种有激情的感觉,很容易就变成了念课文。
为了同时满足自然和严谨,一方面我会先熟记“台词”;另一方面,每次录的时候,我都假想对面有个人,我在对着他缓缓地讲出来。讲到某些地方,我还会假想他对这个知识点是不是有疑问,这样就更加有互动感。
录音频这件事对我的改变非常大。我说话、演讲的时候变得更加严谨了。我会下意识地不去重复已经说过的话。一旦想重复,也闭嘴不发音,等想好了下一句再说。后面,我的录音也越来越顺利,一开始要录五六遍才能成功,后面基本一遍就过了。
创作专栏的过程还有许多事情,都是我很难得的记忆。我很佩服“极客时间”的编辑做专栏时的专业和认真。我也很庆幸,我没有固执地按照自己认为正确的方向和方式来做,而是尊重了他们的专业。很显然,**他们没有我懂技术,但是他们比我<strong><strong>更**</strong>懂“你”。</strong>
专栏结束后,我回看这半年的准备和努力,我发现,**无论对自己的领域多么熟悉,写这个专栏都让我又上升了一个新高度**。
我知道很多技术人都喜欢分享,而写文章又是最容易实现的方式。写文章的时候,可以检验你对基础知识的掌握是否扎实,是不是有换位思考能力,能不能从感性认识上升到理性认知。
除此之外,我觉得最重要的一点是,在创作专栏文章的过程中,我学到了很多技术之外的东西,比如换位思考能力和细节把控的能力。
我在这里记下与“极客时间”的相识和相知。希望看到更多人在极客时间,分享自己的知识和见解。

View File

@@ -0,0 +1,86 @@
你好,我是刘超。
“趣谈网络协议”专栏现在已经全部更新完毕。这里有一份「食用指南」,可以帮你找到学习本专栏的最佳姿势。
在这份指南中,我为你整理了**专栏的所有学习资料**,并告诉你**如何更高效地使用这些资料**,从而帮助你消化吸收,以期获得更好的学习效果。
不管你是刚刚打开这个专栏,还是进入温故的阶段,我的这份指南,都可以帮你更上一个台阶。一起加油吧!
## 1. 能力测试
我从常用的网络协议中精心筛选了核心知识点编成了10道题。这里面的题目和答案都是我精心设计的。希望你一定要先拿出纸笔认真思考记录下自己的答案之后再和文末的详细解析进行对照。
刚刚打开这个专栏的你,可以据此寻找自己的薄弱点,**对症下药**;已经学习了一段时间的你,可以检测学习成果,**查漏补缺**。
点击查看:[网络协议能力测试题](https://time.geekbang.org/column/article/14384)
## 2. 答疑解惑
每篇文章后,我都会留两个思考题,其中第一个问题意在启发你的思考,是对本节内容的延伸学习;第二个问题是为引出下一节,下一节的内容其实就是答案(所以我就不单独解答啦)。
我希望你能够好好地利用这些思考题,毕竟所有的“知”,只有经过了自己的思考之后,才能成为“识”。
如果你是刚刚加入学习,你可以继续在思考题后的“留言区”写下你的答案,学习过程中遇到的问题和思考也欢迎多多分享,我依然会在这里回复你的留言,和你一起讨论。
我知道你肯定也很好奇我对这些问题的思考是怎样的,因此,我针对每一节课后的第一道思考题及留言区比较有代表性的、有深度的问题,特意写了一系列答疑文章。
我再强调一遍,对于这一系列的答疑文章,你一定要在自己进行深度思考之后,再来看文章对比答案,这样可以更有效地拓展你的知识边界。
点击查看:
[第一期第1讲至第2讲答疑解惑合辑](https://time.geekbang.org/column/article/13520)
[第二期第3讲至第6讲答疑解惑合辑](https://time.geekbang.org/column/article/13847)
[第三期第7讲至第13讲答疑解惑合辑](https://time.geekbang.org/column/article/14028)
[第四期第14讲至第21讲答疑解惑合辑](https://time.geekbang.org/column/article/14194)
[第五期第22讲至第36讲答疑解惑合辑](https://time.geekbang.org/column/article/14381)
## 3. 知识串讲
在学习完前面36讲的内容之后我详细讲解了一个“下单”的过程。我把这个过程分为十个阶段从云平台中搭建一个电商开始到BGP路由广播再到DNS域名解析从客户看商品图片到最终下单的整个过程每个步骤我都画了详细的分解图。
你可以用这个过程,串起我们讲过的所有网络协议,还原真实的使用场景,学以致用。我相信,学完前面的详细内容之后,再来看这个串讲内容,你对网络协议一定会有一个全面、深入的把握。
点击查看:
[知识串讲(上篇)](https://time.geekbang.org/column/article/12991)
[知识串讲(中篇)](https://time.geekbang.org/column/article/12996)
[知识串讲(下篇)](https://time.geekbang.org/column/article/13099)
## 4. 知识图谱
专栏中最精华的内容,我都整理在这张图上了。
点击查看:[网络协议知识图谱](https://time.geekbang.org/column/article/14905)
## 5. 实验环境
纸上得来终觉浅。网络是一门实验性很强的学科,我在写专栏的过程中也深深体会到了。有时候,遇到疑问,我常常会拿一个现实的环境,上手操作一下,抓个包看看,这样心里就会有定论。
网络方面最权威的书籍《TCP/IP详解》[TCP/IP illustrated](https://book.douban.com/subject/1741925/)的作者斯蒂文森W. Richard Stevens也是经过无数次实验才完成这本巨著。
因此,我在这本书中的实验基础上,带你搭建一个实验环境,希望你能够上手操作一下学过的知识。毕竟,只有经过你自己动手和思考产生的内容,才是真正属于你的知识。
点击查看我搭建实验环境时候的具体操作,希望给你的思维晋升指路:[《搭建一个网络实验环境:授人以鱼不如授人以渔》](https://time.geekbang.org/column/article/13124)
## 6. 专栏音频
我在这里想特别提一下专栏音频。我的每篇专栏文章都包含了很多图片,为了帮助你更好地理解文章内容,我在录音的时候,常常会对图片做一些补充解释和说明,所以音频和文字稿并非完全一一对应。不知道你具体的学习习惯是怎样的,我建议你除了阅读文字以外,一定要听一下音频,可以利用“**倍速播放**”的功能,还可以自由把控播放速度,更高效地学习。
## 7. 记录,高效;分享,快乐
我们专栏还有不少功能,提醒你好好利用起来,成为高效的学习者。
比如,在学习的过程中,遇到自己不懂的地方,或者是有深刻感受的地方,一定要及时利用“**划线笔记**”的功能,记录下自己当时的想法。这样在过程中点滴积累,等学完后,还可以回过头来再过一遍。如果有可能,你可以把自己的这些思考梳理成文。相信我,这样做,你的提升速度会快到让自己意外。
再比如“**请朋友读**”功能。如果你觉得某篇内容对自己很有帮助,不妨把它推荐给身边有同样需求的朋友,这一个动作或许就能帮他解决一个手边的问题。最重要的是,通过这些分享,你会找到那些和你一样热爱学习的伙伴,一起学习更快乐。
最后,还有一个小小的彩蛋。我把自己这半年写专栏的经历,写成了一篇文章。我是如何写专栏中每一篇文章的?每一篇音频又是如何录出来的?创作专栏给我带来了哪些改变?带你走进“**极客时间万人专栏**”背后的创作故事。
点击查看:[我是如何创作“趣谈网络协议”专栏的?](https://time.geekbang.org/column/article/17846)

View File

@@ -0,0 +1,209 @@
<audio id="audio" title="协议专栏特别福利 | 答疑解惑第一期" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/75/5b/757ec1a4f577ec091171aeffda08885b.mp3"></audio>
你好,我是刘超。
首先感谢大家关注并在留言区写下近3000条留言。留言太多没有及时回复一是每周写三篇文章压力真的挺大的。为了保质保量地产出晚上和周末的时间基本上都搭进去了。二是很多人的留言非常有深度水平很高提的问题一两句话解释不清楚。
每一节结尾我基本都会留两个思考题,其中第一个问题是启发思考的,是对本节内容的延伸学习;第二个问题是为了引出下一节,下一节的内容其实就是答案。
所以我会回答一下每一节的第一个问题,并列出第一个同我的思路最相近的同学,并对留言中比较有代表性的问题,做一个统一的回答,顺便也实现之前要送知识图谱和奖励礼券的承诺。
当然,这并不能说明我的回答就是一定是正确的或者全面的,有很多同学的留言有非常大的信息量,甚至更广的思路,也对这些同学表示感谢。还有些同学指出了我的错误,也感谢你们。
### [《第1讲 | 为什么要学习网络协议?》](https://time.geekbang.org/column/article/7581)
### 课后思考题
当网络包到达一个城关的时候,可以通过路由表得到下一个城关的 IP 地址,直接通过 IP地址找就可以了为什么还要通过本地的MAC地址呢
<img src="https://static001.geekbang.org/resource/image/16/69/16e0b76fe90ce10d8e5c16cad0010e69.png" alt="">
徐良红同学说的比较接近。在网络包里有源IP地址和目标IP地址、源MAC地址和目标MAC地址。从路由表中取得下一跳的IP地址后应该把这个地址放在哪里呢如果放在目标IP地址里面到了城关谁知道最终的目标在哪里呢所以要用MAC地址。
所谓的下一跳看起来是IP地址其实是要通过ARP得到MAC地址将下一跳的MAC地址放在目标MAC地址里面。
### 留言问题
1.MAC地址可以修改吗
<img src="https://static001.geekbang.org/resource/image/b3/1b/b3591518b266a3558f9dd61061c6271b.png" alt="">
<img src="https://static001.geekbang.org/resource/image/3a/5d/3abde3f5607b0278cc87ccfadb88875d.png" alt="">
我查了一下MACMedia Access Control介质访问控制地址也叫硬件地址长度是48比特6字节由16进制的数字组成分为前24位和后24位。
前24位叫作**组织唯一标志符**Organizationally Unique IdentifierOUI是由IEEE的注册管理机构给不同厂家分配的代码用于区分不同的厂家。后24位是厂家自己分配的称为**扩展标识符**。同一个厂家生产的网卡中MAC地址后24位是不同的。
也就是说MAC本来设计为唯一性的但是后来设备越来越多而且还有虚拟化的设备和网卡有很多工具可以修改就很难保证不冲突了。但是至少应该保持一个局域网内是唯一的。
MAC的设计使得即便不能保证绝对唯一但是能保证一个局域网内出现冲突的概率很小。这样一台机器启动的时候就能够在没有IP地址的情况下先用MAC地址进行通信获得IP地址。
好在MAC地址是工作在一个局域网中的因而即便出现了冲突网络工程师也能够在自己的范围内很快定位并解决这个问题。这就像我们生成UUID或者哈希值大部分情况下是不会冲突的但是如果碰巧出现冲突了采取一定的机制解决冲突就好。
2.TCP重试有没有可能导致重复下单
<img src="https://static001.geekbang.org/resource/image/ce/71/ced92fc92921a47918704f1657fb2771.png" alt="">
答案是不会的。这个在[TCP](https://time.geekbang.org/column/article/8975)那一节有详细的讲解。因为TCP层收到了重复包之后TCP层自己会进行去重发给应用层、HTTP层。还是一个唯一的下单请求所以不会重复下单。
那什么时候会导致重复下单呢因为网络原因或者服务端错误导致TCP连接断了这样会重新发送应用层的请求也即HTTP的请求会重新发送一遍。
如果服务端设计的是无状态的,它记不住上一次已经发送了一次请求。如果处理不好,就会导致重复下单,这就需要服务端除了实现无状态,还需要根据传过来的订单号实现幂等,同一个订单只处理一次。
还会有的现象是请求被黑客拦截发送多次这在HTTPS层可以有很多种机制例如通过 Timestamp和Nonce随机数联合起来然后做一个不可逆的签名来保证。
3.TCP报平安的包是原路返回吗
<img src="https://static001.geekbang.org/resource/image/36/ac/361fee74d932bac74f0b26bb280bf2ac.png" alt="">
谢谢语鬼同学的指正。这里的比喻不够严谨,容易让读者产生误会,这里的原路返回的意思是原样返回,也就是返回也是这个过程,不一定是完全一样的路径。
4.IP地址和MAC地址的关系
<img src="https://static001.geekbang.org/resource/image/9c/e3/9c359d2c20ab3f77f5a7e87dcb6fd7e3.png" alt="">
芒果同学的理解非常准确,讲[IP和MAC的关系](https://time.geekbang.org/column/article/7772)的时候说了这个问题。IP是有远程定位功能的MAC是没有远程定位功能的只能通过本地ARP的方式找到。
我个人认为即便有了IPv6也不会改变当前的网络分层模式还是IP层解决远程定位问题只不过改成IPv6了到了本地还是通过MAC。
5.如果最后一跳的时候IP改变了怎么办
<img src="https://static001.geekbang.org/resource/image/08/c1/08029e8c3dce6413558c4819b380c5c1.png" alt="">
对于IP层来讲当包到达最后一跳的时候原来的IP不存在了。比如网线拔掉了或者服务器直接宕机了则ARP就找不到了所以这个包就会发送失败了。对于IP层的工作就结束了。
但是IP层之上还有TCP层TCP会重试的包还是会重新发送但是如果服务器没有启动起来超过一定的次数最终放弃。
如果服务器重启了IP还是原来的IP地址这个时候TCP重新发送的一个包的时候ARP是能够得到这个地址的因而会发到这台机器上来但是机器上面没有启动服务端监听那个端口于是会发送ICMP端口不可达。
如果服务器重启了服务端也重新启动了也在监听那个端口了这个时候TCP的服务端由于是新的Sequence Number根本对不上说明不是原来的连接会发送RST。
那有没有可能有特殊的场景Sequence Number也能对的上呢按照Sequence Number的生成算法是不可能的。
但是有一个非常特殊的方式就是虚拟机的热迁移从一台物理机迁移到另外一台物理机IP不变MAC不变内存也拷贝过去Sequence Number在内存里面也保持住了在迁移的过程中会丢失一两个包但是从TCP来看最终还是能够连接成功的。
6.TCP层报平安怎么确认浏览器收到呢
<img src="https://static001.geekbang.org/resource/image/f3/48/f39ceca92d67db24b42ef9d31f9bff48.png" alt="">
TCP报平安只能保证TCP层能够收到不保证浏览器能够收到。但是可以想象如果浏览器是你写的一个程序你也是通过socket编程写的你是通过socket建立一个TCP的连接然后从这个连接里面读取数据读取的数据就是TCP层确认收到的。
这个读取的动作是本地系统调用大部分情况下不会失败的。如果读取失败呢当然本地会报错你的socket读取函数会返回错误如果你是浏览器程序的实现者你有两种选择一个是将错误报告给用户另一个是重新发送一次请求获取结果显示给用户。
7.ARP协议属于哪一层
<img src="https://static001.geekbang.org/resource/image/e7/9f/e77d85e7260df7611b90a45b7e77ce9f.png" alt="">
ARP属于哪个层一直是有争议的。比如《TCP/IP详解》把它放在了二层和三层之间但是既然是协议只要大家都遵守相同的格式、流程就可以了在实际应用的时候不会有歧义的唯一有歧义的是参加各种考试让你做选择题ARP属于哪一层平时工作中咱不用纠结这个。
## [《第2讲 | 网络分层的真实含义是什么?》](https://time.geekbang.org/column/article/7724)
### 课后思考题
如果你也觉得总经理和员工的比喻不恰当,你有更恰当的比喻吗?
<img src="https://static001.geekbang.org/resource/image/21/27/21cd2dba241413bcfc5bb74fc8dd2527.png" alt="">
<img src="https://static001.geekbang.org/resource/image/3b/3e/3b69f685c893bfd6746ef03c395e8e3e.png" alt="">
我觉得,寄快递和寄信这两个比喻都挺好的。关键是有了封装和解封装的过程。有的同学举了爬楼,或者公司各层之间的沟通,都无法体现封装和解封装的过程。
### 留言问题
1.为什么要分层?
<img src="https://static001.geekbang.org/resource/image/4d/92/4d6c7f391ca5a55fdde3dbf62d69ab92.png" alt="">
是的,仅仅用复杂性来解释分层,太过牵强了。
<img src="https://static001.geekbang.org/resource/image/85/78/856b8040cd0a9f2206ad6f27ad3e9078.png" alt="">
其实这是一个架构设计的通用问题,不仅仅是网络协议的问题。一旦涉及到复杂的逻辑,或者软件需求需要经常变动,一般都会通过分层来解决问题。
假如我们将所有的代码都写在一起但是产品经理突然想调整一下界面这背后的业务逻辑变不变那要不要一起修改呢所以会拆成两层把UI层从业务逻辑中分离出来调用API来进行组合。API不变仅仅界面变是不是就不影响后台的代码了
为什么要把一些原子的API放在基础服务层呢将数据库、缓存、搜索引擎等屏蔽到基础服务层以下基础服务层之上的组合逻辑层、API层都只能调用基础服务层的API不能直接访问数据库。
比如我们要将Oracle切换成MySQL。MySQL有一个库分库分表成为4个库。难道所有的代码都要修改吗当然只要把基础服务层屏蔽提供一致的接口就可以了。
网络协议也是这样的。有的想基于TCP自己不操心就能够保证到达有的想自己实现可靠通信不基于TCP而使用UDP。一旦分了层就好办了定制化后要依赖于下一层的接口只要实现自己的逻辑就可以了。如果TCP的实现将所有的逻辑耦合在了整个七层不用TCP的可靠传输机制都没有办法。
2.层级之间真实的调用方式是什么样的?
<img src="https://static001.geekbang.org/resource/image/95/57/95510f25eb463c4302fb58bd518a8957.png" alt="">
如果文中是一个逻辑图这个问题其实已经到实现层面上来了需要看TCP/IP的协议栈代码了。这里首先推荐一本书《深入理解Linux网络技术内幕》。
其实下层的协议知道上层协议的,因为在每一层的包头里面,都会有上一层是哪个协议的标识,所以不是一个回调函数,每一层的处理函数都会在操作系统启动的时候,注册到内核的一个数据结构里面,但是到某一层的时候,是通过判断到底是哪一层的哪一个协议,然后去找相应的处理函数去调用。
调用的大致过程我这里再讲一下。由于TCP比较复杂我们以UDP为例子其实发送的包就是一个sk_buff结构。这个在[Socket](https://time.geekbang.org/column/article/9293)那一节讲过。
```
int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4)
```
接着UDP层会调用IP层的函数。
```
int ip_send_skb(struct net *net, struct sk_buff *skb)
```
然后IP层通过路由判断最终将包发给下一层。
```
int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb)
```
发送的时候要进行ARP。如果有MAC则调用二层的函数neigh其实就是邻居系统是二层的意思。
```
int neigh_output(struct neighbour *n, struct sk_buff *skb)
```
接收的时候,会调用这里的接收函数。
```
int netif_receive_skb(struct sk_buff *skb)
```
这个函数会根据是ARP或者IP等选择调用不同的函数。如果是IP协议的话就调用这里的函数。
```
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
```
这里也有路由判断。如果是本地的,则继续往上提交这个结构。
```
int ip_local_deliver(struct sk_buff *skb)
```
接着还是根据IP头里面的协议号来判断是什么协议从而调用什么函数。下面这个是对UDP的调用。
```
int udp_rcv(struct sk_buff *skb)
```
3.什么情况下会有下层没上层?
<img src="https://static001.geekbang.org/resource/image/f6/c3/f6414085ec89ba0dfae79436aad2b2c3.png" alt="">
有时候我们自己写应用的时候不一定是直接调用应用层协议的接口例如HTTP等而是自己写Socket编程来约定应用层的协议。再如ping也是一个应用但是它没有用传输层的协议而是用了ICMP的协议。
最后感谢留言次数前15名的同学谢谢你们持之以恒的学习相信你们一定有自己的收获。统计数据截止到2018年8月8日
<img src="https://static001.geekbang.org/resource/image/ca/91/caeec16c4e959e250da1db6c6543b791.jpg" alt="">
同时感谢第1讲、第2讲中对内容有深度思考和提出问题的同学。我会为你们送上奖励礼券和知识图谱。稍后运营同学会发送短信通知。
欢迎你继续提问!
<img src="https://static001.geekbang.org/resource/image/00/5b/0057c2d7c99924366c94c5ed58e3385b.jpg" alt="">

View File

@@ -0,0 +1,368 @@
<audio id="audio" title="协议专栏特别福利 | 答疑解惑第三期" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/6a/17/6a6883051cf676be036547a1f2b47f17.mp3"></audio>
你好,我是刘超。
第三期答疑涵盖第7讲至第13讲的内容。我依旧对课后思考题和留言中比较有代表性的问题作出回答。你可以点击文章名回到对应的章节复习也可以继续在留言区写下你的疑问我会持续不断地解答。希望对你有帮助。
## [《](https://time.geekbang.org/column/article/8445)[第7讲 | ICMP与ping投石问路的侦察兵](https://time.geekbang.org/column/article/8445)[》](https://time.geekbang.org/column/article/8445)
### 课后思考题
当发送的报文出问题的时候会发送一个ICMP的差错报文来报告错误但是如果 ICMP 的差错报文也出问题了呢?
我总结了一下不会导致产生ICMP差错报文的有
<li>
ICMP差错报文ICMP查询报文可能会产生ICMP差错报文
</li>
<li>
目的地址是广播地址或多播地址的IP数据报
</li>
<li>
作为链路层广播的数据报;
</li>
<li>
不是IP分片的第一片
</li>
<li>
源地址不是单个主机的数据报。这就是说,源地址不能为零地址、环回地址、广播地址或多播地址。
</li>
### 留言问题
1.ping使用的是什么网络编程接口
<img src="https://static001.geekbang.org/resource/image/3b/e6/3b2b3f4abaed8a485e8933efbcc304e6.png" alt="">
咱们使用的网络编程接口是Socket对于ping来讲使用的是ICMP创建Socket如下
```
socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)
```
SOCK_RAW就是基于IP层协议建立通信机制。
如果是TCP则建立下面的Socket
```
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
```
如果是UDP则建立下面的Socket
```
socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
```
2.ICMP差错报文是谁发送的呢
我看留言里有很多人对这个问题有疑惑。ICMP包是由内核返回的在内核中有一个函数用于发送ICMP的包。
```
void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info);
```
例如,目标不可达,会调用下面的函数。
```
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
```
当IP大小超过MTU的时候发送需要分片的ICMP。
```
if (ip_exceeds_mtu(skb, mtu)) {
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
goto drop;
}
```
## [《第8讲 | 世界这么大,我想出网关:欧洲十国游与玄奘西行》](https://time.geekbang.org/column/article/8590)
### 课后思考题
当在你家里要访问 163 网站的时候,你的包需要 NAT 成为公网 IP返回的包又要 NAT 成你的私有 IP返回包怎么知道这是你的请求呢它怎么能这么智能地 NAT 成了你的 IP 而非别人的 IP 呢?
这是个比较复杂的事情。在讲云中网络安全里的iptables时我们讲过conntrack功能它记录了SNAT一去一回的对应关系。
如果编译内核时开启了连接跟踪选项那么Linux系统就会为它收到的每个数据包维持一个连接状态用于记录这条数据连接的状态。
<img src="https://static001.geekbang.org/resource/image/a9/fc/a924ccda5d54bcad6f67fdebe0a6c1fc.jpg" alt="">
根据咱们学过的Netfilter的流程图我们知道网络包有三种路径
<li>
发给我的从PREROUTING到INPUT我就接收了
</li>
<li>
我发给别人的从OUTPUT到POSTROUTING就发出去的
</li>
<li>
从我这里经过的从PREROUTING到FORWARD到POSTROUTING。
</li>
如果要跟踪一个网络包,对于每一种路径,都需要设置两个记录点,相当于打两次卡,这样内核才知道这个包的状态。
对于这三种路径,打卡的点是这样设置的:
<li>
发给我的在PREROUTING调用ipv4_conntrack_in创建连接跟踪记录在INPUT调用ipv4_confirm将这个连接跟踪记录挂在内核的连接跟踪表里面。为什么不一开始就挂在内核的连接跟踪表里面呢因为有filter表一旦把包过滤了也就是丢弃了那根本没必要记录这个连接了。
</li>
<li>
我发给别人的在OUTPUT调用ipv4_conntrack_local创建连接跟踪记录在POSTROUTING调用ipv4_confirm将这个连接跟踪记录挂在内核的连接跟踪表里面。
</li>
<li>
从我这里经过的在PREROUTING调用ipv4_conntrack_in创建连接跟踪记录在POSTROUTING调用ipv4_confirm将这个连接跟踪记录挂在内核的连接跟踪表里面。
</li>
网关主要做转发这里主要说的是NAT网关因而我们重点来看“从我这里经过的”这种场景再加上要NAT因而将NAT的过程融入到连接跟踪的过程中来
<li>
如果是PREROUTING的时候先调用ipv4_conntrack_in创建连接跟踪记录
</li>
<li>
如果是PREROUTING的时候有NAT规则则调用nf_nat_ipv4_in进行地址转换
</li>
<li>
如果是POSTROUTING的时候有NAT规则则调用nf_nat_ipv4_out进行地址转换
</li>
<li>
如果是POSTROUTING的时候调用ipv4_confirm将这个连接跟踪记录挂在内核的连接跟踪表里面。
</li>
接下来,我们来看,在这个过程中涉及到的数据结构:连接跟踪记录、连接跟踪表。
在前面讲网络包处理的时候我们说过每个网络包都是一个struct sk_buff它有一个成员变量_nfct指向一个连接跟踪记录struct nf_conn。当然当一个网络包刚刚进来的时候是不会指向这么一个结构的但是这个网络包肯定属于某个连接因而会去连接跟踪表里面去查找之后赋值给sk_buff的这个成员变量。没找到的话就说明是一个新的连接然后会重新创建一个。
连接跟踪记录里面有几个重要的东西:
<li>
nf_conntrack其实才是_nfct变量指向的地址但是没有关系学过C++的话应该明白对于结构体来讲nf_conn和nf_conntrack的起始地址是一样的
</li>
<li>
tuplehash虽然是数组但是里面只有两个IP_CT_DIR_ORIGINAL为下标0表示连接的发起方向IP_CT_DIR_REPLY为下标1表示连接的回复方向。
</li>
```
struct nf_conn {
......
struct nf_conntrack ct_general;
......
struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
......
unsigned long status;
......
}
```
在这里面最重要的是nf_conntrack_tuple_hash的数组。nf_conn是这个网络包对应的一去一回的连接追踪记录但是这个记录是会放在一个统一的连接追踪表里面的。
连接跟踪表nf_conntrack_hash是一个数组数组中的每一项都是一个双向链表的头每一项后面都挂着一个双向链表链表中的每一项都是这个结构。
这个结构的第一项是链表的链nf_conntrack_tuple是用来标识是否同一个连接。
从上面可以看出来,连接跟踪表是一个典型的链式哈希表的实现。
每当有一个网络包来了的时候会将网络包中sk_buff中的数据提取出来形成nf_conntrack_tuple并根据里面的内容计算哈希值。然后需要在哈希表中查找如果找到则说明这个连接出现过如果没找到则生成一个插入哈希表。
通过nf_conntrack_tuple里面的内容可以唯一地标识一个连接
<li>
src包含源IP地址如果是TCP或者UDP包含源端口如果是ICMP包含的是ID
</li>
<li>
dst包含目标IP地址如果是TCP或者UDP包含目标端口如果是ICMP包含的是type, code。
</li>
有了这些数据结构,我们接下来看这一去一回的过程。
当一个包发出去的时候到达这个NAT网关的时候首先经过PREROUTING的时候先调用ipv4_conntrack_in。这个时候进来的包sk_buff为 {源IP客户端IP源端口客户端port目标IP服务端IP目标端口服务端port}将这个转换为nf_conntrack_tuple然后经过哈希运算在连接跟踪表里面查找发现没有说明这是一个新的连接。
于是创建一个新的连接跟踪记录nf_conn这里面有两个nf_conntrack_tuple_hash
<li>
一去:{源IP客户端IP源端口客户端port目标IP服务端IP目标端口服务端port}
</li>
<li>
一回:{源IP服务端IP源端口服务端port目标IP客户端IP目标端口客户端port}。
</li>
接下来经过FORWARD过程假设包没有被filter掉于是要转发出去进入POSTROUTING的过程有NAT规则则调用nf_nat_ipv4_out进行地址转换。这个时候源地址要变成NAT网关的IP地址对于masquerade来讲会自动选择一个公网IP地址和一个随机端口。
为了让包回来的时候能找到连接跟踪记录需要修改两个nf_conntrack_tuple_hash中回来的那一项为{源IP服务端IP源端口服务端port目标IPNAT网关IP目标端口随机端口}。
接下来要将网络包真正发出去的时候除了要修改包里面的源IP和源端口之外还需要将刚才的一去一回的两个nf_conntrack_tuple_hash放入连接跟踪表这个哈希表中。
当网络包到达服务端然后回复一个包的时候这个包sk_buff为{源IP服务端IP源端口服务端port目标IPNAT网关IP目标端口随机端口}。
将这个转换为nf_conntrack_tuple后进行哈希运算在连接跟踪表里面查找是能找到相应的记录的找到nf_conntrack_tuple_hash之后Linux会提供一个函数。
```
static inline struct nf_conn *
nf_ct_tuplehash_to_ctrack(const struct nf_conntrack_tuple_hash *hash)
{
return container_of(hash, struct nf_conn,
tuplehash[hash-&gt;tuple.dst.dir]);
}
```
可以通过nf_conntrack_tuple_hash找到外面的连接跟踪记录nf_conn通过这个可以找到来方向的那个nf_conntrack_tuple_hash{源IP客户端IP源端口客户端port目标IP服务端IP目标端口服务端port}这样就能够找到客户端的IP和端口从而可以NAT回去。
### 留言问题
1.NAT能建立多少连接
<img src="https://static001.geekbang.org/resource/image/3d/d6/3d9249834f730926c2b2f350aba6e1d6.png" alt="">
SNAT多用于内网访问外网的场景鉴于conntrack是由{源IP源端口目标IP目标端口}hash后确定的。
如果内网机器很多但是访问的是不同的外网也即目标IP和目标端口很多这样内网可承载的数量就非常大可不止65535个。
但是如果内网所有的机器都一定要访问同一个目标IP和目标端口这样源IP如果只有一个这样的情况下才受65535的端口数目限制根据原理一种方法就是多个源IP另外的方法就是多个NAT网关来分摊不同的内网机器访问。
如果你使用的是公有云65535台机器应该放在一个VPC里面可以放在多个VPC里面每个VPC都可以有自己的NAT网关。
<img src="https://static001.geekbang.org/resource/image/d0/8d/d08e3a727681751037f715c3f5bd398d.png" alt="">
其实SNAT的场景是内网访问外网存在端口数量的问题也是所有的机器都访问一个目标地址的情况。
如果是微信这种场景应该是服务端在数据中心内部无论多少长连接作为服务端监听的都是少数几个端口是DNAT的场景是没有端口数目问题的只有一台服务器能不能维护这么多连接因而在NAT网关后面部署多个nginx来分摊连接即可。
2.公网IP和私网IP需要一一绑定吗
<img src="https://static001.geekbang.org/resource/image/2d/f1/2d134e61e8cc945c71969be7391b3ff1.png" alt="">
公网IP是有限的如果使用公有云需要花钱去买。但是不是每一个虚拟机都要有一个公网IP的只有需要对外提供服务的机器也即接入层的那些nginx需要公网IP没有公网IP使用SNAT大家共享SNAT网关的公网IP地址也是能够访问的外网的。
我看留言中的困惑点都在于,要区分内主动发起访问外,还是外主动发起访问内,是访问同一个服务端,还是访问一大批服务端。这里就很明白了。
## [《第9讲 | 路由协议:西出网关无故人,敢问路在何方》](https://time.geekbang.org/column/article/8729)
### 课后思考题
路由协议要在路由器之间交换信息,这些信息的交换还需要走路由吗?不是死锁了吗?
<img src="https://static001.geekbang.org/resource/image/b5/da/b5834f4f10c51cb8c91e570bf83f7eda.png" alt="">
OSPF是直接基于IP协议发送的而且OSPF的包都是发给邻居的也即只有一跳不会中间经过路由设备。BGP是基于TCP协议的在BGP peer之间交换信息。
### 留言问题
1.多线BGP机房是怎么回事儿
<img src="https://static001.geekbang.org/resource/image/18/cd/18040a74506276b23e672d2d818d37cd.png" alt="">
BGP主要用于互联网AS自治系统之间的互联BGP的最主要功能在于**控制路由的传播**和**选择最好的路由**。各大运营商都具有AS号全国各大网络运营商多数都是通过BGP协议与自身的AS来实现多线互联的。
使用此方案来实现多线路互联IDC需要在CNNIC中国互联网信息中心或APNIC亚太网络信息中心申请自己的IP地址段和AS号然后通过BGP协议将此段IP地址广播到其它的网络运营商的网络中。
使用BGP协议互联后网络运营商的所有骨干路由设备将会判断到IDC机房IP段的最佳路由以保证不同网络运营商用户的高速访问。
## [《第10讲 | UDP协议因性善而简单难免碰到“城会玩”》](https://time.geekbang.org/column/article/8924)
### 课后思考题
都说 TCP 是面向连接的,在计算机看来,怎么样才算一个连接呢?
赵强强在留言中回答的是正确的。这是TCP的两端为了维护连接所保持的数据结构。
<img src="https://static001.geekbang.org/resource/image/3c/e1/3cba74151564c129057b2cd246a332e1.png" alt="">
<img src="https://static001.geekbang.org/resource/image/95/e0/9507374c04e0908f29d5a3050d905fe0.png" alt="">
## [《第11讲 | TCP协议因性恶而复杂先恶后善反轻松》](https://time.geekbang.org/column/article/8975)
### 课后思考题
TCP 的连接有这么多的状态,你知道如何在系统中查看某个连接的状态吗?
<img src="https://static001.geekbang.org/resource/image/3c/d7/3c997ad09a1c72cbb32a992e7c9588d7.png" alt="">
### 留言问题
1.TIME_WAIT状态太多是怎么回事儿
<img src="https://static001.geekbang.org/resource/image/85/b8/8535df3de9f426b44def750330dcf2b8.png" alt="">
<img src="https://static001.geekbang.org/resource/image/1f/11/1f6a5e17b34f00d28722428b7b8ccb11.jpg" alt="">
如果处于TIMEWAIT状态说明双方建立成功过连接而且已经发送了最后的ACK之后才会处于这个状态而且是主动发起关闭的一方处于这个状态。
如果存在大量的TIMEWAIT往往是因为短连接太多不断的创建连接然后释放连接从而导致很多连接在这个状态可能会导致无法发起新的连接。解决的方式往往是
<li>
打开tcp_tw_recycle和tcp_timestamps选项
</li>
<li>
打开tcp_tw_reuse和tcp_timestamps选项
</li>
<li>
程序中使用SO_LINGER应用强制使用rst关闭。
</li>
当客户端收到Connection Reset往往是收到了TCP的RST消息RST消息一般在下面的情况下发送
<li>
试图连接一个未被监听的服务端;
</li>
<li>
对方处于TIMEWAIT状态或者连接已经关闭处于CLOSED状态或者重新监听seq num不匹配
</li>
<li>
发起连接时超时重传超时keepalive超时
</li>
<li>
在程序中使用SO_LINGER关闭连接时放弃缓存中的数据给对方发送RST。
</li>
2.起始序列号是怎么计算的,会冲突吗?
有同学在留言中问了几个问题。Ender0224的回答非常不错。
<img src="https://static001.geekbang.org/resource/image/af/47/afed5f0593647c0b64971c2fef7e4247.png" alt="">
<img src="https://static001.geekbang.org/resource/image/c3/e1/c39c723c9389c4414401366a32b69fe1.jpg" alt="">
起始ISN是基于时钟的每4毫秒加一转一圈要4.55个小时。
TCP初始化序列号不能设置为一个固定值因为这样容易被攻击者猜出后续序列号从而遭到攻击。 RFC1948中提出了一个较好的初始化序列号ISN随机生成算法。
ISN = M + F (localhost, localport, remotehost, remoteport)
M是一个计时器这个计时器每隔4毫秒加1。F是一个Hash算法根据源IP、目的IP、源端口、目的端口生成一个随机数值。要保证Hash算法不能被外部轻易推算得出用MD5算法是一个比较好的选择。
## [《第12讲 | TCP协议西行必定多妖孽恒心智慧消磨难》](https://time.geekbang.org/column/article/9141)
### 课后思考题
TCP的BBR听起来很牛你知道它是如何达到这个最优点的吗
<img src="https://static001.geekbang.org/resource/image/33/03/33b035bd326e9c1f811d667104a54003.png" alt="">
## [《第13讲 | 套接字SocketTalk is cheap, show me the code》](https://time.geekbang.org/column/article/9293)
### 课后思考题
epoll是Linux上的函数那你知道Windows上对应的机制是什么吗如果想实现一个跨平台的程序你知道应该怎么办吗
<img src="https://static001.geekbang.org/resource/image/74/e9/74d6535a22f5dc8ab2f782b4484ca7e9.png" alt="">
epoll是异步通知当事件发生的时候通知应用去调用IO函数获取数据。IOCP异步传输当事件发生时IOCP机制会将数据直接拷贝到缓冲区里应用可以直接使用。
如果跨平台推荐使用libevent库它是一个事件通知库适用于Windows、Linux、BSD等多种平台内部使用select、epoll、kqueue、IOCP等系统调用管理事件机制。
感谢第7讲至第13讲中对内容有深度思考和提出问题的同学。我会为你们送上奖励礼券和知识图谱。稍后运营同学会发送短信通知。
欢迎你继续提问!
<img src="https://static001.geekbang.org/resource/image/ed/57/edc42141381c0458ab65f70628e88557.jpg" alt="">

View File

@@ -0,0 +1,251 @@
<audio id="audio" title="协议专栏特别福利 | 答疑解惑第二期" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/03/c0/035030be01889cd02f5e909528650bc0.mp3"></audio>
你好,我是刘超。
第二期答疑涵盖第3讲至第6讲的内容。我依旧对课后思考题和留言中比较有代表性的问题作出回答。你可以点击文章名回到对应的章节复习也可以继续在留言区写下你的疑问我会持续不断地解答。希望对你有帮助。
## [《第3讲 | ifconfig最熟悉又陌生的命令行》](https://time.geekbang.org/column/article/7772)
### 课后思考题
你知道 net-tools 和 iproute2 的“历史”故事吗?
<img src="https://static001.geekbang.org/resource/image/02/ba/02ae5ca5ab1c87bf5fea29196725c0ba.png" alt="">
这个问题的答案,盖同学已经写的比较全面了。具体的对比,我这里推荐一篇文章[https://linoxide.com/linux-command/use-ip-command-linux/](https://linoxide.com/linux-command/use-ip-command-linux/),感兴趣的话可以看看。
### 留言问题
1.A、B、C类地址的有效地址范围是多少
<img src="https://static001.geekbang.org/resource/image/eb/c5/ebf13d11cb0bc03d520c6cc4796ee8c5.png" alt="">
我在写的时候,没有考虑这么严谨,平时使用地址的时候,也是看个大概的范围。所以这里再回答一下。
A类IP的地址第一个字段范围是0127但是由于全0和全1的地址用作特殊用途实际可指派的范围是1126。所以我仔细查了一下如果较真的话你在答考试题的时候可以说A类地址范围和A类有效地址范围。
2.网络号、IP地址、子网掩码和广播地址的先后关系是什么
<img src="https://static001.geekbang.org/resource/image/25/56/254f28a3623ca8b4ee368ac02f0cf656.png" alt="">
当在一个数据中心或者一个办公室规划一个网络的时候,首先是网络管理员规划网段,一般是根据将来要容纳的机器数量来规划,一旦定了,以后就不好变了。
假如你在一个小公司里总共就没几台机器对于私有地址一般选择192.168.0.0/24就可以了。
这个时候先有的是网络号。192.168.0就是网络号。有了网络号子网掩码同时也就有了就是前面都是网络号的是1其他的是0广播地址也有了除了网络号之外都是1。
当规划完网络的时候一般这个网络里面的第一个、第二个地址被默认网关DHCP服务器占用你自己创建的机器只要和其他的不冲突就可以了当然你也可以让DHCP服务自动配置。
规划网络原来都是网络管理员的事情。有了公有云之后一般有个概念虚拟网络VPC鼠标一点就能创建一个网络网络完全软件化了任何人都可以做网络规划。
3.组播和广播的意义和原理是什么?
<img src="https://static001.geekbang.org/resource/image/92/f1/92654ed9549bba6c4e609e256ba083f1.png" alt="">
C类地址的主机号8位去掉0和255就只有254个了。
在《TCP/IP详解》这本书里面有两章讲了广播、多播以及IGMP。广播和组播分为两个层面其中MAC层有广播和组播对应的地址IP层也有自己的广播地址和组播地址。
广播相对比较简单MAC层的广播为ff:ff:ff:ff:ff:ffIP层指向子网的广播地址为主机号为全1且有特定子网号的地址。
组播复杂一些MAC层中当地址中最高字节的最低位设置为1时表示该地址是一个组播地址用十六进制可表示为01:00:00:00:00:00。IP层中组播地址为D类IP地址当IP地址为组播地址的时候有一个算法可以计算出对应的MAC层地址。
多播进程将目的IP地址指明为多播地址设备驱动程序将它转换为相应的以太网地址然后把数据发送出去。这些接收进程必须通知它们的IP层它们想接收的发给定多播地址的数据报并且设备驱动程序必须能够接收这些多播帧。这个过程就是“加入一个多播组”。
当多播跨越路由器的时候需要通过IGMP协议告诉多播路由器多播数据包应该如何转发。
4.MTU 1500的具体含义是什么
<img src="https://static001.geekbang.org/resource/image/0b/3d/0b43a6d8c1b77daef705e6b08f40a43d.png" alt="">
MTUMaximum Transmission Unit最大传输单元是二层的一个定义。以以太网为例MTU为1500个Byte前面有6个Byte的目标MAC地址6个Byte的源MAC地址2个Byte的类型后面有4个Byte的CRC校验共1518个Byte。
在IP层一个IP数据报在以太网中传输如果它的长度大于该MTU值就要进行分片传输。如果不允许分片DF就会发送ICMP包这个在[ICMP](https://time.geekbang.org/column/article/8445)那一节讲过。
在TCP层有个MSSMaximum Segment Size最大分段大小它等于MTU减去IP头再减去TCP头。即在不分片的情况下TCP里面放的最大内容。
在HTTP层看来它的body没有限制而且在应用层看来下层的TCP是一个流可以一直发送但其实是会被分成一个个段的。
## [《第4讲 | DHCP与PXEIP是怎么来的又是怎么没的》](https://time.geekbang.org/column/article/8015)
### 课后思考题
PXE 协议可以用来安装操作系统,但是如果每次重启都安装操作系统,就会很麻烦。你知道如何使得第一次安装操作系统,后面就正常启动吗?
<img src="https://static001.geekbang.org/resource/image/8d/c2/8db1eca548b4eaacfd9fbbb544a467c2.png" alt="">
一般如果咱们手动安装一台电脑的时候,都是有启动顺序的,如果改为硬盘启动,就没有问题了。
<img src="https://static001.geekbang.org/resource/image/05/cc/053273db99e6ef2458fcf48a534ac4cc.png" alt="">
好在服务器一般都提供IPMI接口可以通过这个接口启动、重启、设置启动模式等等远程访问这样就可以批量管理一大批机器。
<img src="https://static001.geekbang.org/resource/image/8f/09/8f423b7215d40642f8c712250b65b709.png" alt="">
这里提到Cobbler这是一个批量安装操作系统的工具。在OpenStack里面还有一个Ironic也是用来管理裸机的。有兴趣的话可以研究一下。
### 留言问题
1.在DHCP网络里面手动配置IP地址会冲突吗?
<img src="https://static001.geekbang.org/resource/image/6c/bc/6cd736774a770fe0ca5e6d42ad3425bc.png" alt="">
<img src="https://static001.geekbang.org/resource/image/62/d0/62b7fbe964db964060d501e3ef5252d0.png" alt="">
在一个DHCP网络里面如果某一台机器手动配置了一个IP地址并且在DHCP管理的网段里的话DHCP服务器是会将这个地址分配给其他机器的。一旦分配了ARP的时候就会收到两个应答IP地址就冲突了。
当发生这种情况的时候应该怎么办呢DHCP的过程虽然没有明确如何处理但是DHCP的客户端和服务器都可以添加相应的机制来检测冲突。
如果由客户端来检测冲突一般情况是客户端在接受分配的IP之前先发送一个ARP看是否有应答有就说明冲突了于是发送一个DHCPDECLINE放弃这个IP地址。
如果由服务器来检测冲突DHCP服务器会发送ping来看某个IP是否已经被使用。如果被使用了它就不再将这个IP分配给其他的客户端了。
2.DHCP的Offer和ACK应该是单播还是广播呢
<img src="https://static001.geekbang.org/resource/image/2c/b0/2c3c71b16ffca3442ffb60c36de8dcb0.png" alt="">
<img src="https://static001.geekbang.org/resource/image/a6/68/a6745f6d648ce8819976fed6fdc82468.png" alt="">
没心没肺 回答得很正确。
这个我们来看[DHCP的RFC](http://www.faqs.org/rfcs/rfc2131.html),我截了个图放在这儿:
<img src="https://static001.geekbang.org/resource/image/5b/ba/5ba44ea86352594b78c30ce75cc123ba.jpg" alt="">
这里面说了几个问题。
正常情况下一旦有了IP地址DHCP Server还是希望通过单播的方式发送OFFER和ACK。但是不幸的是有的客户端协议栈的实现如果还没有配置IP地址就使用单播。协议栈是不接收这个包的因为OFFER和ACK的时候IP地址还没有配置到网卡上。
所以一切取决于客户端的协议栈的能力如果没配置好IP就不能接收单播的包那就将BROADCAST设为1以广播的形式进行交互。
如果客户端的协议栈实现很厉害即便是没有配置好IP仍然能够接受单播的包那就将BROADCAST位设置为0就以单播的形式交互。
3.DHCP如何解决内网安全问题?
<img src="https://static001.geekbang.org/resource/image/f7/8c/f7ff8bed68c94247a19772113d87e18c.png" alt="">
其实DHCP协议的设计是基于内网互信的基础来设计的而且是基于UDP协议。但是这里面的确是有风险的。例如一个普通用户无意地或者恶意地安装一台DHCP服务器发放一些错误或者冲突的配置再如有恶意的用户发出很多的DHCP请求让DHCP服务器给他分配大量的IP。
对于第一种情况DHCP服务器和二层网络都是由网管管理的可以在交换机配置只有来自某个DHCP服务器的包才是可信的其他全部丢弃。如果有SDN或者在云中非法的DHCP包根本就拦截到虚拟机或者物理机的出口。
对于第二种情况一方面进行监控对DHCP报文进行限速并且异常的端口可以关闭一方面还是SDN或者在云中除了被SDN管控端登记过的IP和MAC地址其他的地址是不允许出现在虚拟机和物理机出口的也就无法模拟大量的客户端。
## [《第5讲 | 从物理层到MAC层如何在宿舍里自己组网玩联机游戏》](https://time.geekbang.org/column/article/8094)
### 课后思考题
1.在二层中我们讲了 ARP 协议,即已知 IP 地址求 MAC还有一种 RARP 协议,即已知 MAC 求 IP 的,你知道它可以用来干什么吗?
<img src="https://static001.geekbang.org/resource/image/e3/51/e3f91712382b9322beb02ec3d12ce851.png" alt="">
2.如果一个局域网里面有多个交换机ARP 广播的模式会出现什么问题呢?
盖还说出了环路的问题。
<img src="https://static001.geekbang.org/resource/image/74/a8/74de5ae71807bd0ee3d95f44d7e82aa8.png" alt="">
没心没肺不但说明了问题,而且说明了方案。
<img src="https://static001.geekbang.org/resource/image/fa/a4/fa42fea4d9b4b8ed75008e3f1eadd7a4.png" alt="">
## [《第6讲 | 交换机与VLAN办公室太复杂我要回学校》](https://time.geekbang.org/column/article/8386)
### 课后思考题
STP 协议能够很好地解决环路问题,但是也有它的缺点,你能举几个例子吗?
<img src="https://static001.geekbang.org/resource/image/b4/61/b4cb0842468ab9bb16916e9fb29ccb61.png" alt="">
<img src="https://static001.geekbang.org/resource/image/ee/a1/eebc423ca8a37fbc3e7dfc06f07e4ea1.png" alt="">
STP的主要问题在于当拓扑发生变化新的配置消息要经过一定的时延才能传播到整个网络。
由于整个交换网络只有一棵生成树,在网络规模比较大的时候会导致较长的收敛时间,拓扑改变的影响面也较大,当链路被阻塞后将不承载任何流量,造成了极大带宽浪费。
## 留言问题
1.每台交换机的武力值是什么样的?
<img src="https://static001.geekbang.org/resource/image/ae/51/ae72cc32931fc72918dd2f5da0ea9e51.png" alt="">
<img src="https://static001.geekbang.org/resource/image/c2/d8/c24fe02c21f41449a3a896442bc3b4d8.png" alt="">
当一台交换机加入或者离开网络的时候,都会造成网络拓扑变化,这个时候检测到拓扑变化的网桥会通知根网桥,根网桥会通知所有的网桥拓扑发生变化。
网桥的ID是由网桥优先级和网桥MAC地址组成的网桥ID最小的将成为网络中的根桥。默认配置下网桥优先级都一样默认优先级是32768。这个时候MAC地址最小的网桥成为根网桥。但是如果你想设置某台为根网桥就配置更小的优先级即可。
在优先级向量里面Root Bridge ID就是根网桥的IDBridge ID是网桥的IDPort ID就是一个网桥上有多个端口端口的ID。
<img src="https://static001.geekbang.org/resource/image/c0/95/c04244bf0b91ae964871698e7811d695.png" alt="">
按照RFC的定义ROOT PATH COST是和出口带宽相关的具体的数据如下
<img src="https://static001.geekbang.org/resource/image/d6/b9/d606b2c9f636ea3bc5694ac95d51f7b9.jpg" alt="">
2.图中的LAN指的是什么
<img src="https://static001.geekbang.org/resource/image/48/83/48efc105d54eff1ca6099e44df5c5a83.png" alt="">
在这一节中,这两张图引起了困惑。
<img src="https://static001.geekbang.org/resource/image/a5/85/a57a66bf97d326fd0b1355a0ba844e85.png" alt="">
<img src="https://static001.geekbang.org/resource/image/92/17/92450a4c1d7f261a3fbf06a12d621d17.png" alt="">
本来是为了讲二层的原理,做了个抽象的图,结果引起了大家的疑问,所以这里需要重新阐述一下。
首先这里的LAN1、LAN2、LAN 3的说法的确不准确因为通过网桥或者交换机连接它们还是属于一个LAN其实这是三个物理网络通过网桥或者交换机连接起来形成一个二层的LAN。
对于一层也即物理层的设备主要使用集线器Hub这里我们就用Hub将物理层连接起来。
于是我新画了两个图。
<img src="https://static001.geekbang.org/resource/image/ea/48/ea499064396aa5078b9fe9cd5f4fcc48.png" alt="">
<img src="https://static001.geekbang.org/resource/image/7d/e5/7d0ec3b857e7c85bba8aefc340a86ce5.png" alt="">
在这里我用Hub将不同的机器连接在一起形成一个物理段而非LAN。
3.在MAC地址已经学习的情况下ARP会广播到没有IP的物理段吗
<img src="https://static001.geekbang.org/resource/image/1f/f4/1f0ae48921ea404705d93e8bcbf4daf4.png" alt="">
<img src="https://static001.geekbang.org/resource/image/0c/a8/0c5d8df850a2fff54c175789645bd7a8.png" alt="">
首先谢谢这两位同学指出错误这里ARP的目标地址是广播的所以无论是否进行地址学习都会广播而对于某个MAC的访问在没有地址学习的时候是转发到所有的端口的学习之后只会转发到有这个MAC的端口。
4.802.1Q VLAN 和Port-based VLAN有什么区别
<img src="https://static001.geekbang.org/resource/image/98/4d/988673f41c561228c017e96435ea264d.png" alt="">
所谓Port-based VLAN一般只在一台交换机上起作用比如一台交换机10个口1、3、5、7、9属于VLAN 10。1发出的包只有3、5、7、9能够收到但是从这些口转发出去的包头中并不带VLAN ID。
而802.1Q的VLAN出了交换机也起作用也就是说一旦打上某个VLAN则出去的包都带这个VLAN也需要链路上的交换机能够识别这个VLAN进行转发。
感谢第3讲至第6讲中对内容有深度思考和提出问题的同学。我会为你们送上奖励礼券和知识图谱。稍后运营同学会发送短信通知。
欢迎你继续提问!
<img src="https://static001.geekbang.org/resource/image/c6/9c/c65176654fe6305665399da89cfe909c.jpg" alt="">

View File

@@ -0,0 +1,265 @@
<audio id="audio" title="协议专栏特别福利 | 答疑解惑第五期" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/64/18/64d2e85a551930e15c4537ba6e0d1518.mp3"></audio>
你好,我是刘超。
第五期答疑涵盖第22讲至第36讲的内容。我依旧对课后思考题和留言中比较有代表性的问题作出回答。你可以点击文章名回到对应的章节复习也可以继续在留言区写下你的疑问我会持续不断地解答。希望对你有帮助。
## [《第22讲 | VPN朝中有人好做官》](https://time.geekbang.org/column/article/10386)
### 课后思考题
当前业务的高可用性和弹性伸缩很重要,所以很多机构都会在自建私有云之外,采购公有云,你知道私有云和公有云应该如何打通吗?
<img src="https://static001.geekbang.org/resource/image/88/2b/882fbc4105dcfb68e9da055065ad0f2b.jpg" alt="" />
### 留言问题
DH算法会因为传输随机数被破解吗
<img src="https://static001.geekbang.org/resource/image/59/b5/5985bcc89e863897eecb18097e8430b5.jpg" alt="" />
这位同学的[笔记](https://mubu.com/doc/1cZYndRrAg)特别认真让人感动。DH算法的交换材料要分公钥部分和私钥部分公钥部分和其他非对称加密一样都是可以传输的所以对于安全性是没有影响的而且传输材料远比传输原始的公钥更加安全。私钥部分是谁都不能给的因此也是不会截获到的。
## [《第23讲 | 移动网络:去巴塞罗那,手机也上不了脸书》](https://time.geekbang.org/column/article/10534)
### 课后思考题
咱们上网都有套餐,有交钱多的,有交钱少的,你知道移动网络是如何控制不同优先级的用户的上网流量的吗?
这个其实是PCRF协议进行控制的它可以下发命令给PGW来控制上网的行为和特性。
## [《第24讲 | 云中网络:自己拿地成本高,购买公寓更灵活》](https://time.geekbang.org/column/article/10742)
### 课后思考题
为了直观这一节的内容我们以桌面虚拟化系统举例。在数据中心里面有一款著名的开源软件OpenStack这一节讲的网络连通方式对应OpenStack中的哪些模型呢
<img src="https://static001.geekbang.org/resource/image/dd/c2/dde85e3ca5c02dfcde75b8bb96a264c2.jpg" alt="" />
OpenStack的早期网络模式有Flat、Flat DHCP、VLAN后来才有了VPC用VXLAN和GRE进行隔离。
## [《第25讲 | 软件定义网络:共享基础设施的小区物业管理办法》](https://time.geekbang.org/column/article/10755)
### 课后思考题
在这一节中提到了通过VIP可以通过流表在不同的机器之间实现负载均衡你知道怎样才能做到吗
可以通过ovs-ofctl下发流表规则创建group并把端口加入group中所有发现某个地址的包在两个端口之间进行负载均衡。
```
sudo ovs-ofctl -O openflow11 add-group br-lb &quot;group_id=100 type=select selection_method=dp_hash bucket=output:1 bucket=output:2&quot;
sudo ovs-ofctl -O openflow11 add-flow br-lb &quot;table=0,ip,nw_dst=192.168.2.0/24,actions=group:100&quot;
```
### 留言问题
SDN控制器是什么东西
<img src="https://static001.geekbang.org/resource/image/e5/a4/e5401b93f60da5b95fdc0e060a0a51a4.jpg" alt="" />
SDN控制器是一个独立的集群主要是在管控面因为要实现一定的高可用性。
主流的开源控制器有OpenContrail、OpenDaylight等。当然每个网络硬件厂商都有自己的控制器而且可以实现自己的私有协议进行更加细粒度的控制所以江湖一直没有办法统一。
流表是在每一台宿主机上保存的,大小限制取决于内存,而集中存放的缺点就是下发会很慢。
## [《第26讲 | 云中的网络安全:虽然不是土豪,也需要基本安全和保障》](https://time.geekbang.org/column/article/10978)
### 课后思考题
这一节中重点讲了iptables的filter和nat功能iptables还可以通过QUEUE实现负载均衡你知道怎么做吗
我们可以在iptables里面添加下面的规则
```
-A PREROUTING -p tcp -m set --match-set minuteman dst,dst -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j NFQUEUE --queue-balance 50:58
-A OUTPUT -p tcp -m set --match-set minuteman dst,dst -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j NFQUEUE --queue-balance 50:58
```
NFQUEUE的规则表示将把包的处理权交给用户态的一个进程。queue-balance表示会将包发给几个queue。
libnetfilter_queue是一个用户态库用户态进程会使用libnetfilter_queue连接到这些queue中将包读出来根据包的内容做决策后再放回内核进行发送。
## [《第27讲 | 云中的网络QoS邻居疯狂下电影我该怎么办》](https://time.geekbang.org/column/article/10994)
### 课后思考题
这一节中提到,入口流量其实没有办法控制,出口流量是可以很好控制的,你能想出一个控制云中的虚拟机的入口流量的方式吗?
<img src="https://static001.geekbang.org/resource/image/0a/26/0ae24cd15cda3eb8aba91666650d1526.jpg" alt="" />
在云平台中,我们可以限制一个租户的默认带宽,我们仍然可以配置点对点的流量控制。
在发送方的OVS上我们可以统计发送方虚拟机的网络统计数据上报给管理面。在接收方的OVS上我们同样可以收集接收方虚拟机的网络统计数据上报给管理面。
当流量过大的时候,我们虽然不能控制接收方的入口流量,但是我们可以在管理面下发一个策略,控制发送方的出口流量。
### 留言问题
对于HTB借流量的情况借出去的流量能够抢回来吗
<img src="https://static001.geekbang.org/resource/image/ec/79/ec406e7e9502859e9b6b80c04d703979.jpg" alt="" />
首先,借出去的流量,当自己使用的时候,是能够抢回来的。
有一篇著名的文章[《HTB Linux queuing discipline manual》](http://luxik.cdi.cz/~devik/qos/htb/manual/userg.htm)里面很详细,你可以看看。
<img src="https://static001.geekbang.org/resource/image/2b/0b/2bf7de23e5bda856c606a73f66dd050b.jpg" alt="" />
很多人看不懂这是一棵HTB树有三个分支。A用户使用www访问网页SMTP协议发送邮件B用户不限协议。
在时间0的时候0、1、2都以90k的速度发送数据也即A用户在访问网页同时发送邮件B也在上网干啥都行。
在时间3的时候将0的发送停止A不再访问网页了红色的线归零A的总速率下来了剩余的流量按照比例分给了蓝色的和绿色的线也即分给了A发邮件和B上网。
在时间6的时候将0的发送重启为90k也即A重新开始访问网页则蓝色和绿色的流量返还给红色的流量。
在时间9的时候将1的发送停止A不再发送邮件了绿色的流量为零A的总速率也下来了剩余的流量按照比例分给了蓝色和红色。
在时间12将1的发送恢复A又开始发送邮件了红色和蓝色返还流量。
在时间15将2的发送停止B不再上网了啥也不干了蓝色流量为零剩余的流量按照比例分给红色和绿色。
在时间19将1的发送停止A不再发送邮件了绿色的流量为零所有的流量都归了红色所有的带宽都用于A来访问网页。
## [《第28讲 | 云中网络的隔离GRE、VXLAN虽然住一个小区也要保护隐私》](https://time.geekbang.org/column/article/11324)
### 课后思考题
虽然VXLAN可以支持组播但是如果虚拟机数目比较多在Overlay网络里面广播风暴问题依然会很严重你能想到什么办法解决这个问题吗
<img src="https://static001.geekbang.org/resource/image/c3/0e/c354402836976d9defcf67d36ba2ae0e.jpg" alt="" />
很多情况下物理机可以提前知道对端虚拟机的MAC地址因而当发起ARP请求的时候不用广播全网只要本地返回就可以了在Openstack里面称为L2Population。
## [《第29讲 | 容器网络:来去自由的日子,不买公寓去合租》](https://time.geekbang.org/column/article/11465)
### 课后思考题
容器内的网络和物理机网络可以使用NAT的方式相互访问如果这种方式用于部署应用有什么问题呢
<img src="https://static001.geekbang.org/resource/image/68/25/683db80f520ddc094817d5e780099025.jpg" alt="" />
_CountingStars对这个问题进行了补充。
<img src="https://static001.geekbang.org/resource/image/97/3f/978d279627a1388c54c2eb2466cd0d3f.jpg" alt="" />
其实就是性能损耗随机端口占用看不到真实IP。
## [《第30讲 | 容器网络之Flannel每人一亩三分地》](https://time.geekbang.org/column/article/11643)
### 课后思考题
通过 Flannel 的网络模型可以实现容器与容器直接跨主机的互相访问,那你知道如果容器内部访问外部的服务应该怎么融合到这个网络模型中吗?
<img src="https://static001.geekbang.org/resource/image/ac/83/acb3aef79240c8707f70491604dbde83.jpg" alt="" />
Pod内到外部网络是通过docker引擎在iptables的POSTROUTING中的MASQUERADE规则实现的将容器的地址伪装为node IP出去回来时再把包nat回容器的地址。
有的时候我们想给外部的一个服务使用一个固定的域名这就需要用到Kubernetes里headless service的ExternalName。我们可以将某个外部的地址赋给一个Service的名称当容器内访问这个名字的时候就会访问一个虚拟的IP。然后在容器所在的节点上由iptables规则映射到外部的IP地址。
## [《第31讲 | 容器网络之Calico为高效说出善意的谎言》](https://time.geekbang.org/column/article/11940)
### 课后思考题
将Calico部署在公有云上的时候经常会选择使用IPIP模式你知道这是为什么吗
_CountingStars的回答是部分正确的。
<img src="https://static001.geekbang.org/resource/image/17/a2/1769832623a4a14e4bc79a67b3e522a2.jpg" alt="" />
一个原因是中间有路由如果VPC网络是平的但是公有云经常会有一个限制那就是器的IP段是用户自己定义的一旦出虚拟机的时候云平台发现不是它分配的IP很多情况下直接就丢弃了。如果是IPIP出虚拟机之后IP还是虚拟机的IP就没有问题。
## [《第32讲 | RPC协议综述远在天边近在眼前》](https://time.geekbang.org/column/article/12230)
### 课后思考题
在这篇文章中mount的过程是通过系统调用最终调用到RPC层。一旦mount完毕之后客户端就像写入本地文件一样写入NFS了这个过程是如何触发RPC层的呢
_CountingStars的回答很有深度。
<img src="https://static001.geekbang.org/resource/image/7a/60/7ab3228c9cb73e7f0cf0b922332d1d60.jpg" alt="" />
是的是通过VFS实现的。
在讲[Socket](https://time.geekbang.org/column/article/9141)那一节的时候我们知道在Linux里面很多东西都是文件因而内核中有一个打开的文件列表File list每个打开的文件都有一项。
<img src="https://static001.geekbang.org/resource/image/60/8c/602d09290bd4f9e0183f530e9653348c.jpg" alt="" />
对于Socket来讲in-core inode就是内存中的inode。对于nfs来讲也有一个inode这个inode里面有一个成员变量file_operations这里面是这个文件系统的操作函数。对于nfs来讲因为有nfs_file_read、nfs_file_write所以在一个mount的路径中读取某个文件的时候就会调用这两个函数触发RPC远程调用服务端。
## [《第33讲 | 基于XML的SOAP协议不要说NBA请说美国职业篮球联赛》](https://time.geekbang.org/column/article/12388)
### 课后思考题
对于HTTP协议来讲有多种方法但是SOAP只用了POST这样会有什么问题吗
<img src="https://static001.geekbang.org/resource/image/8a/19/8a889ea32a5a404c432a1102b90a4819.jpg" alt="" />
## [《第34讲 | 基于JSON的RESTful接口协议我不关心过程请给我结果》](https://time.geekbang.org/column/article/12512)
### 课后思考题
在讨论RESTful模型的时候举了一个库存的例子但是这种方法有很大问题那你知道为什么要这样设计吗
<img src="https://static001.geekbang.org/resource/image/4a/a2/4ab1e3cb5b48a843d6dc5967cc1238a2.jpg" alt="" />
这个我在双十一包的例子中已经分析过了。
## [《第35讲 | 二进制类RPC协议还是叫NBA吧总说全称多费劲》](https://time.geekbang.org/column/article/12521)
### 课后思考题
对于微服务模式下的RPC框架的选择Dubbo和SpringCloud各有优缺点你能做个详细的对比吗
<img src="https://static001.geekbang.org/resource/image/49/33/49d571110301eab5cf61560bfee2f333.jpg" alt="" />
## [《第36讲 | 跨语言类RPC协议交流之前双方先来个专业术语表》](https://time.geekbang.org/column/article/12819)
### 课后思考题
在讲述Service Mesh的时候我们说了希望Envoy能够在服务不感知的情况下将服务之间的调用全部代理了你知道怎么做到这一点吗
<img src="https://static001.geekbang.org/resource/image/0b/d3/0b13bbed598d0d9b9a783d1a3fa881d3.jpg" alt="" />
<img src="https://static001.geekbang.org/resource/image/56/f8/56e282315a2ef361aa0a8bb1cf0b38f8.jpg" alt="" />
iptables规则可以这样来设置
首先定义的一条规则是ISTIO_REDIRECT转发链。这条链不管三七二十一都将网络包转发给envoy的15000端口。但是一开始这条链没有被挂到iptables默认的几条链中所以不起作用。
接下来在PREROUTING规则中使用这个转发链。从而进入容器的所有流量都被先转发到envoy的15000端口。而envoy作为一个代理已经被配置好了将请求转发给productpage程序。
当productpage往后端进行调用的时候就碰到了output链。这个链会使用转发链将所有出容器的请求都转发到envoy的15000端口。
这样无论是入口的流量还是出口的流量全部用envoy做成了“汉堡包”。envoy根据服务发现的配置做最终的对外调用。
这个时候iptables规则会对从envoy出去的流量做一个特殊处理允许它发出去不再使用上面的output规则。
感谢第22讲至第36讲中对内容有深度思考和提出问题的同学。我会为你们送上奖励礼券和知识图谱。稍后运营同学会发送短信通知。
<img src="https://static001.geekbang.org/resource/image/90/99/90874109328ea2f88d097f58dddc4e99.jpg" alt="" />
咱们的答疑环节暂时告一段落了,如果你在学习过程中有什么问题,欢迎你继续留言给我!

View File

@@ -0,0 +1,207 @@
<audio id="audio" title="协议专栏特别福利 | 答疑解惑第四期" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/ad/d4/ad9d6ddf788e6c9a1d7cb9b771901fd4.mp3"></audio>
你好,我是刘超。
第四期答疑涵盖第14讲至第21讲的内容。我依旧对课后思考题和留言中比较有代表性的问题作出回答。你可以点击文章名回到对应的章节复习也可以继续在留言区写下你的疑问我会持续不断地解答。希望对你有帮助。
## [《第14讲 | HTTP协议看个新闻原来这么麻烦》](https://time.geekbang.org/column/article/9410)
### 课后思考题
QUIC是一个精巧的协议所以它肯定不止今天我提到的四种机制你知道还有哪些吗
云学讲了一个QUIC的特性。
<img src="https://static001.geekbang.org/resource/image/4e/02/4eb79fc072ad11cf3e938616259f0502.png" alt="">
QUIC还有其他特性一个是**快速建立连接**。这个我放在下面HTTPS的时候一起说。另一个是**拥塞控制**QUIC协议当前默认使用了TCP协议的CUBIC拥塞控制算法
你还记得TCP的拥塞控制算法吗每当收到一个ACK的时候就需要调整拥塞窗口的大小。但是这也造成了一个后果那就是RTT比较小的窗口增长快。
然而这并不符合当前网络的真实状况因为当前的网络带宽比较大但是由于遍布全球RTT也比较长因而基于RTT的窗口调整策略不仅不公平而且由于窗口增加慢有时候带宽没满数据就发送完了因而巨大的带宽都浪费掉了。
CUBIC进行了不同的设计它的窗口增长函数仅仅取决于连续两次拥塞事件的时间间隔值窗口增长完全独立于网络的时延RTT。
CUBIC的窗口大小以及变化过程如图所示。
<img src="https://static001.geekbang.org/resource/image/fe/5f/fe9fb6d6e9deea8c3543f54572ec765f.jpg" alt="">
当出现丢包事件时CUBIC会记录这时的拥塞窗口大小把它作为Wmax。接着CUBIC会通过某个因子执行拥塞窗口的乘法减小然后沿着立方函数进行窗口的恢复。
从图中可以看出一开始恢复的速度是比较快的后来便从快速恢复阶段进入拥塞避免阶段也即当窗口接近Wmax的时候增加速度变慢立方函数在Wmax处达到稳定点增长速度为零之后在平稳期慢慢增长沿着立方函数的开始探索新的最大窗口。
### 留言问题
HTTP的keepalive模式是什么样
<img src="https://static001.geekbang.org/resource/image/77/7c/77df27b180a8d0390322bd9137d21d7c.png" alt="">
在没有keepalive模式下每个HTTP请求都要建立一个TCP连接并且使用一次之后就断开这个TCP连接。
使用keepalive之后在一次TCP连接中可以持续发送多份数据而不会断开连接可以减少TCP连接建立次数减少TIME_WAIT状态连接。
然而长时间的TCP连接容易导致系统资源无效占用因而需要设置正确的keepalive timeout时间。当一个HTTP产生的TCP连接在传送完最后一个响应后还需要等待keepalive timeout秒后才能关闭这个连接。如果这个期间又有新的请求过来可以复用TCP连接。
## [《第15讲 | HTTPS协议点外卖的过程原来这么复杂》](https://time.geekbang.org/column/article/9492)
### 课后思考题
HTTPS 协议比较复杂,沟通过程太繁复,这样会导致效率问题,那你知道有哪些手段可以解决这些问题吗?
通过HTTPS访问的确复杂至少经历四个阶段DNS查询、TCP连接建立、TLS连接建立最后才是HTTP发送数据。我们可以一项一项来优化这个过程。
首先如果使用基于UDP的QUIC可以省略掉TCP的三次握手。至于TLS的建立如果按文章中基于TLS 1.2的双方要交换key经过两个来回也即两个RTT才能完成握手。但是咱们讲IPSec的时候讲过通过共享密钥、DH算法进行握手的场景。
在TLS 1.3中握手过程中移除了ServerKeyExchange和ClientKeyExchangeDH参数可以通过key_share进行传输。这样只要一个来回就可以搞定RTT了。
对于QUIC来讲也可以这样做。当客户端首次发起QUIC连接时会发送一个client hello消息服务器会回复一个消息里面包括server config类似于TLS1.3中的key_share交换。当客户端获取到server config以后就可以直接计算出密钥发送应用数据了。
### 留言问题
1.HTTPS的双向认证流程是什么样的
<img src="https://static001.geekbang.org/resource/image/93/39/934a64552c3c8c04c629383db0d6b939.jpg" alt="">
2.随机数和premaster的含义是什么
<img src="https://static001.geekbang.org/resource/image/28/78/28a3938ab8efaf9fa7f313a46d0e1478.jpg" alt="">
## [《第16讲 | 流媒体协议:如何在直播里看到美女帅哥?》](https://time.geekbang.org/column/article/9688)
### 课后思考题
你觉得基于 RTMP 的视频流传输的机制存在什么问题?如何进行优化?
Jason的回答很对。
<img src="https://static001.geekbang.org/resource/image/38/90/38d8dda78c277a01f85cbf7371639c90.png" alt="">
Jealone的回答更加具体。
<img src="https://static001.geekbang.org/resource/image/c3/d9/c384054368a1f491a34ac7f6f0641dd9.png" alt="">
当前有基于自研UDP协议传输的也有基于QUIC协议传输的。
### 留言问题
RTMP建立连接的序列是什么样的
<img src="https://static001.geekbang.org/resource/image/ad/53/ada59a46a4c5d5194c322ddb34250d53.png" alt="">
的确,这个图我画错了,我重新画了一个。
<img src="https://static001.geekbang.org/resource/image/5a/75/5a45685536eb1c1ae354c3cc1e037275.jpg" alt="">
不过文章中这部分的文字描述是没问题的。
客户端发送C0、C1、 C2服务器发送S0、 S1、 S2。
首先客户端发送C0表明自己的版本号不必等对方的回复然后发送C1表明自己的时间戳。
服务器只有在收到C0的时候才能返回S0表明自己的版本号。如果版本不匹配可以断开连接。
服务器发送完S0后也不用等什么就直接发送自己的时间戳S1。客户端收到S1的时候发一个知道了对方时间戳的ACK C2。同理服务器收到C1的时候发一个知道了对方时间戳的ACK S2。
于是,握手完成。
## [《第17讲 | P2P协议我下小电影99%急死你》](https://time.geekbang.org/column/article/9707)
### 课后思考题
除了这种去中心化分布式哈希的算法,你还能想到其他的应用场景吗?
<img src="https://static001.geekbang.org/resource/image/fe/eb/fe12f0f41edbb4f46c3df513988760eb.png" alt="">
### 留言问题
99%卡住的原因是什么?
<img src="https://static001.geekbang.org/resource/image/4e/da/4e52188839de11d46050935c2a3f12da.png" alt="">
## [《第18讲 | DNS协议网络世界的地址簿》](https://time.geekbang.org/column/article/9895)
### 课后思考题
全局负载均衡使用过程中,常常遇到失灵的情况,你知道具体有哪些情况吗?对应应该怎么来解决呢?
<img src="https://static001.geekbang.org/resource/image/e3/28/e3ce7238d7fa1d7e5d9568def5832b28.jpeg" alt="">
### 留言问题
如果权威DNS连不上怎么办
<img src="https://static001.geekbang.org/resource/image/92/06/92579a426910452422521f6bce71be06.png" alt="">
一般情况下DNS是基于UDP协议的。在应用层设置一个超时器如果UDP发出没有回应则会进行重试。
DNS服务器一般也是高可用的很少情况下会挂。即便挂了也会很快切换重试一般就会成功。
对于客户端来讲为了DNS解析能够成功也会配置多个DNS服务器当一个不成功的时候可以选择另一个来尝试。
## [《第19讲 | HttpDNS网络世界的地址簿也会指错路》](https://time.geekbang.org/column/article/9938)
### 课后思考题
使用 HttpDNS需要向 HttpDNS 服务器请求解析域名,可是客户端怎么知道 HttpDNS 服务器的地址或者域名呢?
<img src="https://static001.geekbang.org/resource/image/c3/e1/c3ca8a189ac6ad10afaca2da185c5ce1.png" alt="">
## [《第20讲 | CDN你去小卖部取过快递么》](https://time.geekbang.org/column/article/10085)
### 课后思考题
这一节讲了CDN使用DNS进行全局负载均衡的例子CDN如何使用HttpDNS呢
<img src="https://static001.geekbang.org/resource/image/c8/d9/c86f4fa153ff64ebaa1335933779cad9.png" alt="">
## [《第21讲 | 数据中心:我是开发商,自己拿地盖别墅》](https://time.geekbang.org/column/article/10098)
### 课后思考题
对于数据中心来讲,高可用是非常重要的,每个设备都要考虑高可用,那跨机房的高可用,你知道应该怎么做吗?
其实跨机房的高可用分两个级别,分别是**同城双活**和**异地灾备**。
<img src="https://static001.geekbang.org/resource/image/8a/71/8af9a0a7c1d24b73d26ab0ef5f54b071.jpg" alt="">
**同城双活**就是在同一个城市距离大概30km到100km的两个数据中心之间通过高速专线互联的方式让两个数据中心形成一个大二层网络。
同城双活最重要的是,数据如何从一个数据中心同步到另一个数据中心,并且在一个数据中心故障的时候,实现存储设备的切换,保证状态能够快速切换到另一个数据中心。在高速光纤互联情况下,主流的存储厂商都可以做到在一定距离之内的两台存储设备的近实时同步。数据双活是一切双活的基础。
基于双数据中心的数据同步可以形成一个统一的存储池从而数据库层在共享存储池的情况下可以近实时地切换例如Oracle RAC。
虚拟机在统一的存储池的情况下也可以实现跨机房的HA在一个机房切换到另一个机房。
SLB负载均衡实现同一机房的各个虚拟机之间的负载均衡。GSLB可以实现跨机房的负载均衡实现外部访问的切换。
如果在两个数据中心距离很近并且大二层可通的情况下也可以使用VRRP协议通过VIP方式进行外部访问的切换。
下面我们说**异地灾备**。
<img src="https://static001.geekbang.org/resource/image/e5/94/e561d8a5ec5842a67513ba42bda09494.jpg" alt="">
异地灾备的第一大问题还是数据的问题,也即生产数据中心的数据如何备份到容灾数据中心。由于异地距离比较远,不可能像双活一样采取近同步的方式,只能通过异步的方式进行同步。可以预见的问题是,容灾切换的时候,数据会丢失一部分。
由于容灾数据中心平时是不用的,不是所有的业务都会进行容灾,否则成本太高。
对于数据的问题,我比较建议从业务层面进行容灾。由于数据同步会比较慢,可以根据业务需求高优先级同步重要的数据,因而容灾的层次越高越好。
例如,有的用户完全不想操心,直接使用存储层面的异步复制。对于存储设备来讲,它是无法区分放在存储上的虚拟机,哪台是重要的,哪台是不重要的,只会完全根据块进行复制,很可能就会先复制了不重要的虚拟机。
如果用户想对虚拟机做区分,则可以使用虚拟机层面的异步复制。用户知道哪些虚拟机更重要一些,哪些虚拟机不重要,则可以先同步重要的虚拟机。
对业务来讲,如果用户可以根据业务层情况,在更细的粒度上区分数据是否重要。重要的数据,例如交易数据,需要优先同步;不重要的数据,例如日志数据,就不需要优先同步。
在有异地容灾的情况下,可以平时进行容灾演练,看容灾数据中心是否能够真正起作用,别容灾了半天,最后用的时候掉链子。
感谢第14讲至第21讲中对内容有深度思考和提出问题的同学。我会为你们送上奖励礼券和知识图谱。稍后运营同学会发送短信通知。
欢迎你继续提问!
<img src="https://static001.geekbang.org/resource/image/7e/7e/7e172a2e3bb3cbc926d138dd2bd9297e.jpg" alt="">

View File

@@ -0,0 +1,21 @@
<audio id="audio" title="第2季回归 | 这次我们来“趣谈Linux操作系统”" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/3a/69/3abcd0c589a74d612cdd5ff5c1c18169.mp3"></audio>
你好我是你的老朋友刘超。在“趣谈网络协议”结课半年之后我又给你带来了一个新的基础课程“趣谈Linux操作系统”。
在咱们“趣谈网络协议”的留言里,我和同学们进行了很多互动,同时,我也和其他做基础知识专栏的作者有了不少交流,我发现,无论是从个人的职业发展角度,还是从公司招聘候选人的角度来看,扎实的基础知识是很多人的诉求。这让我更加坚信,我应该在“趣谈基础知识”这条道路上走下去。
**在设计“趣谈Linux操作系统”专栏的时候我仍然秉承“趣谈”和“故事化”的方式将枯燥的基础知识结合某个场景给你生动、具象地讲述出来帮你加深理解、巩固记忆、夯实基础。**
在我看来,操作系统在计算机中承担着“大管家”的角色,这个“大管家”就好比一家公司的老板,我们的目标就是把这家公司做上市,具体的过程,我用了一张图来表示:
<img src="https://static001.geekbang.org/resource/image/7d/a5/7d7b2f705d4877bb331b4ea3ff3450a5.jpg" alt="">
Linux操作系统中的概念非常多数据结构也很多流程也复杂一般人在学习的过程中很容易迷路。我希望能够将这些复杂的概念、数据结构、流程通俗地讲解出来争取每篇文章都用一张图串起这篇的知识点。
最终,整个专栏下来,你如果能把这些图都掌握了,你的知识就会形成体系和连接。在此基础上再进行深入学习,就会如鱼得水、易如反掌。
一段新的征途即将开始期待与你继续同行。为了感谢老同学我为你送上一张10元专属优惠券可以与限时优惠同享优惠券有效期仅5天建议你抓紧使用。点击下方图片可试读专栏最新文章。
我们新专栏见!
[<img src="https://static001.geekbang.org/resource/image/57/44/57f047be7ebb1f4aba7e8064e1c11544.jpg" alt="">](https://time.geekbang.org/column/intro/164?utm_term=zeusOLMNR&amp;utm_source=app&amp;utm_medium=geektime&amp;utm_campaign=164-presell&amp;utm_content=qutanwangluoxieyi)