7.7 网络(二)

接上篇:7.7 网络(一)_龙赤子的博客-CSDN博客

目录

 三 操作系统涉及的网络内容

  1 网络栈

  2 协议

  3 应用


  操作系统涉及的网络内容

  1 网络栈

   这里我们重点讨论操作系统里面的网络。这部分在整个网络架构中,属于端的技术。对于端来讲,要么是数据的生产者,要么是数据的消费者,所以主要任务就是数据的收发处理。其实这种收发也离不开分析处理,本质上,仍然是管道上的一截。如何来理解这一点呢?想想看,数据本身在线路上是不是不被处理?根据二进制的0和1调制而成的波形,是根据物理规律,在线路上以接近光的速度一路狂奔,原样到达对端。因此,中间的路由器,也是属于一个端点,虽然我们更常用节点来称呼。只有端点,才能收发数据,处理数据,只不过,在这些所谓的“节点”端点上,更多的是处理如何转发数据。这种差异,并不影响大家对网络及其协议的理解。基于前面的网络拓扑图,我们可以参考下图来理解这一点:

上面这幅图片来自下面这本经典的网络教材,国内是有引进影印版的,现在据说到了第七版。对计算机网络感兴趣的读者,可以买来看看。

   过滤掉本节第一幅图中的路由器等中间节点,只看红色箭头连接的两个端点。我们可以用下图来更清晰的展示这个过程:

   这个图的最底层部分,我们在前面的网络传输部分,已经看到过了。物理层就是网卡硬件负责的事情了,而网络接口层和物理层之间,就是驱动跟网卡的衔接之处。

   其实,从上图可以明显的看出,整个传输系统有两个管道,一个是最底层的物理管道,一个是在其之上,由对等节点构成的逻辑管道(右边部分为了展示解封装,去掉了各个层的头部,特此说明)。一个物理管道加n个逻辑管道,构成了操作系统的网络系统。而逻辑管道,又是大部分计算机网络教材所重点讲述的部分。

   在物理管道之上,其实是有两层关系的。一层是上面所述的,通过水平关系展示的逻辑管道;一层则是通过上下关系展示的封装栈道。如果要用四个字来描述计算机的网络,就可以用上下左右这四个字来概括了。计算机网络所要解决的,也就是这两个关系问题:上下问题和左右问题。上下问题解决数据如何建,左右问题解决数据如何传。

   关于数据如何建,也就是数据如何封装的问题,前面已有论述到,主要是建立一套约定的规则,大家遵守规则,这样接收方才能解封装。这套规则,就叫协议。但是,协议不仅仅要封装数据,就如在网络传输部分所说的,通道存在丢失数据的可能性,因此,这里的协议,还需要处理数据的可靠传输问题,也就是数据如何传的问题。可见,只要搞定了协议,就搞定了网络。

   但是,网络要处理的问题很多很多,如果只用一两个协议来囊括网络的所有内容,那么协议就会显得过于臃肿和复杂。所以,为了简化问题的处理,进一步的,人们把这些问题分开处理,划分成许多层,每层只关注问题的一个方面,处理一个抽象层面的内容。比如,如下图所示,ISO将网络划分为七层。其中,应用层关注数据如何应对业务的问题;传输层关注数据可靠与否及如何处理丢失、重复、乱序等问题;而网络层则只是关注数据如何路由的问题;最后,链路层关注与底层物理通道的衔接。这样,应用层将数据交给传输层传输,传输层又将数据交给网络层路由,网络层又将数据交给链路层发送。这样,一层衔接一层,最终完成数据传输任务。

   分层是个好主意,但是分太多层,则问题处理又显得过于啰嗦,容易出现边界不清、职责不明确的问题,反而将问题复杂化。因此,计算机网络中,实际常用的是上图中间的四层结构。

   层分好了,新的问题又来了。虽然通过分层,问题得到了简化,但是网络传输的需求是多种多样的。为了完成某个层的任务,实际中发现,通过一两个协议搞定一个层,也似乎是过于绝对了。尤其是对应用层,业务种类千变万化,视频的、音频的、文字的,各有各的特点,因此,要高效利用网络,还得继续切割。这样,每个层又可以划分为多个协议, 每一个协议只处理一个相对独立的问题,如此一来,就形成了一个协议栈簇,如下图所示:

   整个协议栈就像搭积木,一层一层,一块一块构建起来的,如下图所示:

   上面图中所示的协议类型,只是作为例子说明问题。实际中协议的数量和种类远远不止这些。另外,栈也只是为了形象的说明协议簇的构成。又因为协议栈中,TCP和IP这两个协议最为流行,也最为基础,因此,这个协议栈就常常叫做TCP/IP协议栈。这就是我们常说的 TCP/IP协议栈叫法的来由。

  2 协议

   通过前面的内容,我们了解到,网络栈主要由协议构成,这里我们来看看协议是做什么用的,有哪些共性的东西。

   协议在计算机网络中的重要性不言而喻。但是,协议到底是指什么呢?从名称上,我们可以直观的感受到,协议应该是一套行为准则及其约束规则。一件事情,做什么、怎么做、有哪些约束(时间、“地点”等),这些就是协议要解决的问题。

   没有接触过具体协议的读者,根据上面所述的内容,可能还是会有太抽象、太缥缈,无法触摸的感觉。即使是开始学习计算机网络的读者,大部分对协议的理解也是有限。可能觉得自己懂了,但是,真正要用起来,还是会无处下手。记得笔者当年学习计算机网络时,有一个作业是实现一个邮件收发的客户端。老师只给了协议要求,没有提其他约束,也就是语言不限,平台不限,选自己熟悉的来。界面也不限,只看最后功能结果。那时,虽然在课堂上,协议二字已经听到过无数次了,但是当真正要编码实现时,不知该如何入手。最关键的是,不知道该如何使用给的邮件“协议”。这就是对协议的理解过于抽象的缘故,说白了,就是没有实际具体的感受一下,协议是什么,怎么用。

   摒弃传统教科书的概念,我们先用一种较为通俗的说法来解释协议二字。我认为,协议是数据封装加逻辑处理。就是说,数据该怎么封装,有哪些字段,协议需要说明,这是基础。然后,基于封装所用到的数据字段,来定义一套运行流程。当然,也可以反过来,先定义一套运行流程,比如有限状态机。然后再根据流程的运行需要,定义所需的字段。一般来讲,协议中所定义的流程,在逻辑上需要是完备的。但是大部分并不能通过数学语言来严格的证明,就如计算机里的很多算法一样,正确性难以通过数学模型来证明。因此,协议可能存在漏洞。

   对协议的完整理解,实际上是需要通过语法、语义、语用三个层面来把握的。

   首先,语法层面。语法层面主要涵盖了协议的字段构成。这跟我们平常交流的语言是类似的。“我吃饭”是一个合规的主谓宾结构,大家都按此来。如果有人说“我饭吃”,听者大概是可以理解的,但是在计算机世界里,严格的数学要求,是不允许出现这种病句的。这类“病句”在接收端是无法正确解析的。所以,要想互联互通,就要遵守协议的格式要求。

   其次,语义层面。语义层面主要是展示一条协议要表达的具体含义。协议中应该包含哪些字段,这就是语义要求的。我们日常沟通中,一句话可能长,也可能短,这是由沟通要传达的信息所决定的,协议也类似。以常见的网络媒体流播放协议RTSP为例,就包括了流描述、建立、播放、暂停、终止等多条具体协议。每一条的字段都是为完成这条协议的任务而设定的。

   最后,语用层面。语用层面主要是整体的反映协议的功能作用,涵盖了协议的逻辑流程。就像我们的文章是由很多句子构成的,协议要干成一件事,很多时候,也是通过多条具体的协议组合来完成的。还是以前面的RTSP为例,在语用层面,体现的就是播放媒体这件事的过程。要做这件事,需要先发现支持哪些媒体格式,然后建立媒体会话,之后播放。播放过程中可能出现暂停、恢复反复交替的过程。最后,终止会话,释放资源。这个严密设计的流程,体现的就是语用层面的内容。

   通过上面的内容,我们再来理解协议的概念,可能就更清晰具体一些了。回到前面邮件作业的例子,当时无处下手,就是因为没有一个具体的东西可以辅助来理解协议的概念。后来,我发现,通过抓包学习网络,尤其是协议,倒是一个好方法。读者如果感兴趣,可以试试。如果笔者当时知道这个方法,那么,完成那个邮件客户端的作业,也就不会那么痛苦了。这里,以RTSP协议为例,一个抓包的结果如下:

   虽然可以通过上面三个层面来理解协议,但是,有些协议实现的并不那么简明,相反,因为要处理的问题本身就比较复杂,所以协议的设计和实现也相对复杂许多。TCP就是这样一个典型例子。除此,协议毕竟是要计算机处理的,虽然作用类似我们沟通交流的语言,但是,要照顾到机器的需求,因此很多信息是隐含在字段中的,这就是为啥协议要通过学习才能理解的原因。举个例子,拿TCP的超时重传来讲,协议中可能只包含确认序号,而不会直接提供是否超时,是否需要重传的信息,因此,协议的实现者要通过确认序号字段和上下文,自己判断是否超时了,是否需要重传。

   在前面提到,网络可能存在的丢包,让可靠传输的设计陡然变复杂了许多。这种复杂性,主要在于处理很多细节的问题。就本质而言,TCP实现可靠传输无外乎两大法宝,一个是确认,一个是重传。首先,通过确认,判断数据是否可靠到达了对端。如果没有,那么就通过重传,将数据再传输一次,然后再次确认,直到数据到达目的端。

   了解了协议是什么后,我们再来看看协议的实现。

   协议毕竟不是语言,能够变化无穷。相反,机器能够处理的情况都是有限的,这是图灵机理论上的要求。因此,实际中,无论协议多么的复杂,其运作流程,都可以通过一个有限状态机来描述。如果一个不够,那就来多个。这不是开玩笑,而是有实际例子的。笔者之前搞过PPP协议的实现,当时,那是我遇到的最复杂的协议处理。我将其称为多层螺旋结构,如下图所示:

   在这种多层螺旋结构中,每一层都是一个状态机。下层状态机成功后,就跃迁到上层状态机。直到最高层的状态机,负责最终的数据传输。当当前层的状态机出现错误后,就回落到下一层的状态机,继续协商处理。PPP就是这样的一种协议。代码中,针对每一个状态机,定义了处理接口,也定义了状态机之间的迁移关系。简单表示,如下图所示:

   一般而言,协议的规范文档中,都会对事件的处理和状态迁移做出说明,开发者实现时,只需要按照规范文档做就可以了,不需要自己设计状态机。这种对协议的使用,相对而言是比较简单的,真正复杂的是协议设计。针对一个问题,如何设计一套逻辑完备的协议作为解决方案,这才是真正考验开发者的。因为这个过程中,需要通过整体把握,考虑很多因素,作出很多取舍决策,才能完成目标。标准制定者,就是在干这项工作,其工作输出结果就是我们学习的各种协议。

   提这一点,是因为国内的教学,都是倾向于输出标准答案,而忽略了研究思考的过程。这种灌输式的方式,其实是很影响创新的。不过,我前面建议大家去看的那本计算机网络教材,有一个很大的不同,就是采用启发的方式,引导读者不断思考如何设计一个可靠传输协议。通过这样一步一步的迭代,完成对TCP协议的讲解,因此,很值得读者细细品味。

  3 应用

   通过上面的介绍,相信大家对协议有了基本的认识。协议设计大家可能会遇到,但对大部分读者而言,使用操作系统的网络栈开发网络应用,可能才是常态。那么,如何使用协议栈来开发网络应用呢?下面,我们就对这部分内容进行一些介绍。

   首先,我们常见的或者用到的网络应用,大部分都是基于套接字程序来实现的。操作系统网络栈展现出来的接口有两个层面,一个是垂直方向的套接字接口,用于实现数据的收发;一个是水平方向的配置接口,用于管理网络。如下图所示:

   套接字位于传输层之上,也就是说,通过套接字,可以实现应用层的协议。当然,这也不绝对,操作系统一般也提供RAW类型的套接字,方面应用实现传输层的协议。关于套接字接口的使用,有一套标准流程,大家可以在网络上搜索相关的例子来学习。应用软件开发者构造好自己的数据后,就可以交给套接字接口,由套接字接口协助将其发送给对端。接收端通过套接字接口拿到的就是发送端原样的数据。至于数据该如何解释,这就是应用层协议负责的事情了。我们可以这样来理解,收发端的套接字接口共同组成了一个虚拟的传输通道。

   套接字接口的相关内容本身并不复杂。但是,网络编程却并不简单。这其中的难点在于性能优化上。如何实现高性能的并发处理,是网络编程进阶的关键所在。在这一点上,不仅仅是应用设计者,相关SDK设计者,甚至操作系统设计者都在持续的优化。感兴趣的读者,可以去了解异步IO相关的一些内容,这里就不再展开了。

   关于套接字编程,这里最后再补充一点。我们用的手机、电脑等产品,其上跑的网络应用丰富多彩,而且很多是同时在用的,所以,通过套接字接口构建的虚拟通道,在一台设备上,可以存在多个,且每个彼此是独立的,可以认为相互不影响(排除对内存、带宽等资源的占用影响)。不仅仅是设备级别,即使在一个应用中,这种虚拟通道也可能存在很多个。虚拟通道的关键构建元素是网络五元组,即{源地址、源端口、协议、目的地址、目的端口},所以,设备节点间的虚拟通道是N:N的映射关系。早年笔者接触过BT协议下载软件,对此还是深有感触的。下面这幅图,是当时理解多个下载上传通道时画的。

   好了,关于网络的介绍就到这里,希望本文对大家理解计算机网络有所帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙赤子

你的小小鼓励助我翻山越岭

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值