noteless 阅读(12) 评论(0)
本文对计算机网络通信的原理进行简单的介绍
首先从网络协议分层的概念进行介绍,然后对TCP、IP协议族进行了概念讲解,然后对操作系统关于通信抽象模型进行了简单介绍,最后简单描述了socket
 

分层的概念

基本概念

TCP/IP协议族本身很复杂,本人也暂时还没有“详解TCP/IP”的想法,本系列相关的文章都是意在从宏观上建立一个认知。
想要理解TCP/IP协议族,核心就是要理解分层的概念。
到底什么是分层?
假如说有A,B这么两个部门,每个部门有一个经理和一个秘书,有一些事情没必要开会或者直接交流,比如文件的签署,可能是这样的:
A经理拿一份文件给a秘书,然后a秘书将文件交给b秘书,b秘书然后又交给B经理,B经理签字后,又依次通过b秘书,a秘书,最后到达A经理处
image_5c32c22e_4f5a
如上图所示,蓝色和红色箭头表示实际经过的路径
但是对于A经理来说,他在意的肯定是文件被B经理签字,B经理在意的肯定是签字后的文件到达A经理处;
对于秘书们来说也是如此,他们不会直接对接经理,他们对接的是相对应的秘书;
所以,对于经理这一层次来说,他们如同直接跟对方经理交流,下层(秘书)向上层透明的提供服务,a秘书具体是如何将文件交给b秘书的,面对面交付?邮寄交付?这些经理才不会关心,从这个角度可以认为,下层(秘书)对上层(经理)提供了透明的服务,上层只需要关注下层提供正确的服务即可。
所以,分层就是层层交付,下层向上层提供服务(比如基层领导向上级领导汇报工作,上级领导继续向上级领导汇报工作,直到中央领导....)
对于上层来说,如同两个对等层之间直接交流,他们不关心底层的细节与实现,底层的存在是透明的
如果你只是为了完成任务而调用别人提供的接口,你除了数据的正确性以外,你关心实现细节么?
为什么要分层?
首先说,计算机网络(整个计算机科学)几乎没有什么事情是先有成熟的理论,然后再有完整(完美)的实现,这么按部就班的事情,大多数都是实践促进理论发展,理论让实现更完美。
世界各地运行着各种各样的不同的计算机、通信设备、网络线路等等,网络环境非常复杂,如何能够形成大一统的完整方案?显然是非常困难的,如果有一种协议在各种网络环境中都能很好的工作,那不就是万能协议了?
比如说如果从南京到拉萨,如果全程只让你选择一种交通工具,应该很难或者说没有任何一种选择在各个路段上都是最佳选择。
最佳的选择就是在不同的路段上,选择最合适的出行方式,比如从家坐地铁到机场,然后坐飞机,然后火车......
网络协议分层也是这个理念,既然环境那么复杂,那我们就分层处理,不同层次实现不同的任务,负责向上层正确交付。

TCP/IP层次结构

image_5c32c22e_70b5
TCPIP分层介绍
如上图所示,现有的TCP、IP协议是分层次的。
在分层体系结构中,各层之间是完全独立的,某一层并不需要知道他的下一层是如何实现的,而仅仅是需要知道下层提供的服务
由于每一层都只是实现一种相对独立的功能,因而可以将一个难以处理的复杂问题分解为若干个小问题。
 
应用层
应用层是体系结构中的最高层,应用层是通过应用进程间的交互来完成特定网络应用。
应用层协议定义的是应用进程间通信和交互的规则。这里的进程就是主机中正在运行的程序。
应用层交互的数据单元称之为报文
运输层
运输层为两台主机之间的通信提供通用的数据传输服务,应用进程利用该服务传输传送应用层报文
运输层提供通用的服务,也就是说不针对特定的网络应用,而是多种应用可以使用同一个传输层服
运输层主要两种协议
传输控制协议TCP (Transmission Control Protocol)—提供面向连接的、可靠的数据传输服务,其数据传输的单位是报文段
用户数据报协议UDP (User Datagram Protocol)—提供无连接的、尽最大努力(best-effort)的数据传输服务(不保证数据传输的可靠性),其数据传输的单位是用户数据报。
网际层   
网际层负责为分组交换网上的不同主机提供通信服务
在发送数据时,网际层把运输层产生的报文段或用户数据报封装成分组或包进行传送
在TCP/IP体系中,由于网际层使用IP协议,因此分组也叫做IP数据报,或简称为数据报
网络层的另一个任务就是要选择合适的路由,使源主机运输层所传下来的分组,能够通过网络中的路由器找到目的主机。
网络接口层
TCP/IP模型中并没有对网络接口层进行准确地定义,仅仅要求能够通过网络设备传输IP数据包,也就是为IP数据报的发送和接收服务
网络接口层相当于OSI模型中的数据链路层和物理层
数据链路层通常简称为链路层,两台主机数据传输,总是要经过一段段的链路,这就需要使用专门的链路层协议
在两个相邻节点之间传送协议时,链路层将网络层传递过来的IP数据报封装成帧,在两个相邻的链路上传递帧
每一帧包括数据和必要的控制信息
在接收消息时,控制信息能够提供足够的信息让接收端能够识别一个帧从哪个比特开始到哪个比特结束。
这样链路层收到数据之后,就可以提取出来数据部分,上交给网络层。
而物理层规定了数据在物理媒体上传递的一些协议,比如电缆的插头应该有多少引脚,在物理层上传输的是比特。
image_5c32c22e_5a5b
在每层中,又都运行着不同的协议
image_5c32c22e_7774
从这一点也更好的能看得出来,分层设计的好处,每一层都可以根据本层的特点,使用不同的软硬件方案,从而既灵活又高效。
上层和下层的关系,就如同经理和秘书,秘书向经理层提供服务;而各层次中运行的协议就好比a秘书是如何将文件交给b秘书一样,是面对面交付?还是邮寄?这就是同一层次中的协议的概念。

快递包裹的分层运输

下图为之前淘宝时一个快递的轨迹
image_5c32c22e_878
卖家作为发送方,将商品打包(小箱子)注明收件人信息,地址+姓名+电话。
当地的快递点会进行收件,收件后会统一装箱(大箱子)发到公司
公司会装车发往下一站转运中心
经过1个或者多个转运中心,期间可能经过一次或者多次的装车、卸车过程,到达目的地转运中心
从最近的转运中心卸车,将车内货物发往指定公司
公司继续将大箱子拆解发往不同的营业厅
营业厅快递员将一件或者多件快递送到指定地址(地址可能是一个公司,可能是一个小区,也可能是一个学校,绝大多数地址一般都不能确定一个人)
最终根据电话号码联系最终的收件人进行收件
这就完成了整个运输的过程。
 
整个过程中,只有寄件人和收件人知道运输的到底是什么东西
从寄件人处的营业厅,到当地公司,到转运中心,再到收件人相关的转运中心,再到当地公司,再到最终营业厅
一个不断装箱,装车,卸车,拆箱的过程,他们对具体的货品完全不知道,仅仅负责运输。
快递被分解为多个阶段,或者说是多个不同层次进行运输
image_5c32c22e_792e

网络数据的分层运输

image_5c32c22e_65b9
如上图所示,计算机网络中,数据的传输也是类似快递运输的过程。
  • 应用层对应着操作系统中运行的各类应用软件
  • 传输层、网际层以及网络接口层对应着操作系统、网卡、网卡驱动程序。
  • 而中间的网际层、网络接口层又对应着路由器、交换机等通信设备
最终实现了计算机两个进程的通信。
 
聊QQ时,你脑子里面应该没有路由器这个东西,你感觉到的应该只是你在跟对方聊QQ
也就是你在你电脑上聊天窗口中输入内容,对方的QQ窗口中间就会接到消息,所以说下层对上层就是透明的。
网络协议是属于标准、规范、纲领,计算机操作系统中可以实现所需要的功能,路由器、交换机等网络设备中也会实现所需要的部分功能;
尽管网络协议分层明确,但是协议是协议,实现是实现,在具体的实现上,在实现上往往是有交织的。
你没办法说“XXX设备只是实现了哪一层”,比如三层交换机就是具有部分路由器功能的交换机
 
在快递的运输过程中,在所有的节点上不断地进行着装箱,装车,卸车,拆箱的过程,直到货物到达收件人手中。
在计算机网络通信中,数据从应用层准备好之后,类似装箱的过程,不断地进行封装,添加TCP头部,添加IP头部,添加MAC头部,不断转发,到达最终的接收方。

包的格式

包的基本结构为头部和数据,每一层的包(段)都是如此,上一层的数据到下一层变为数据,然后添加对应的头部。
比如最初的快递盒子到了卡车上,应该是被装到袋子(箱子)里面,变成了数据,然后这个袋子(箱子)也会被贴上下一站的标签。
image_5c32c22e_2647

层层包装与运输

如下图所示,最初的应用层数据(卖家发出的快递盒子),被放到了运输层,添加TCP头部(放入编织袋,贴上新的标签)
然后又进入到网际层,添加了IP头部(类似将指定目的地的货搬上车运输),然后又进入到链路层,添加MAC头部,最终到达目的地
所以,网络数据的传递,跟快递的层层逻辑,有很大的相似性。
image_5c32c22f_4b7e
 
image_5c32c22f_547a

层次功能简介

应用层是应用之间通信的协议
比如,在软件X中,我们约定如果我发了GET三个字母给你,你就把你的某个内容回传给我,这就是应用层的协议。
从数据传输交换的角度看,应用层并不涉及数据传输,应用层产生的数据,是被运输的“货物”。
 
运输层真正的完成了数据端到端的传送---从一台计算机的一个端点传输到另一台计算机中的一个端点
网络中有很多计算机,每一台计算机中可以同时运行多个应用程序
如同同一个公司地址,可以有很多收件人
将消息传送到某一台计算机的某个应用程序,这就是端到端的传送,类似通过地址+姓名手机唯一定位一个收件人
运输层仅仅运行于主机上,并不会运行于网络传输设备上,比如路由器,他们都不涉及运输层协议
 
从数据真正运输的角度看,起最大作用的是网际层,将数据从一台计算机传输到另一台计算机的整个过程。
网际层将传输层数据进一步封装,在网络上进行传递,也是路由器需要的协议
通过网际层可以确定数据报的方向,但是具体的传输还是要依靠物理设备,所以网络接口层(链路层物理层)负责每一段的具体转发。
 
总结下就是:
  • 应用层产生数据,并且注明收件人地址、姓名电话
  • 运输层将数据进行封装,添加TCP头,真正开始打包运输,相当于收件
  • 网络层将数据运送到目的主机
  • 接收方的运输层又负责将数据运送到指定程序
  • 目的程序解读数据按照应用层协议进行响应
 
网络接口层完成了每一段物理链路上数据的传送,网际层完成了发送方主机到接收方主机数据的传送
运输层在大门口接收到了数据解析后,将数据运送到指定程序
应用层读取数据
image_5c32c22f_18e
计算机网络的各层以及其协议的集合,就是网络的体系结构,而网络的体系结构是计算机网络通信的概念理论
是抽象的协议概念,而实现是具体的,是真正的运行在计算机中的硬件和软件

操作系统与网络通信

协议说的再好听,终归也仍旧是协议,你讲加一个TCP头部,头部内容是XXX....,那么落实到最具体,可能是这样子:
你可能有一个结构体对应的是TCP格式的报文,然后你malloc一段内存空间,将接收到的数据放入这段内存中,然后计算头部,将头部数据进行设置......(我就是随便说说)
所以,这才是通信的实现,所以说,计算机网络就是各种设备对网络协议的各部分的实现以及对接。
通信依赖的是相关的硬件设备(路由器、交换机、甚至计算机)以及运行其上的实现了各部分协议的软件,简言之,通信依赖的就是硬件+软件。
对于网络设备的硬件的制造以及协议实现是华为、思科那种大厂关注的范畴,有N多程序猿默默地付出
而对于一般的应用程序员来说,我们首先会关注的就是如何编写网络程序?
对绝大多数程序猿来说,都是面向某个编程语言进行程序开发,而编程语言中最终需要依赖于操作系统底层提供服务。
假设说,Java提供了一个方法“爆炸”,调用这个方法,电脑真的会爆炸么?恐怕不会,因为计算机以及操作系统就没有这个功能。
所以我们需要了解下操作系统对通信的支持。

操作系统本身也是一种软件,负责管理计算机硬件资源,是应用程序与计算机硬件之间的中间层,将应用程序与计算机硬件解耦。 

进程是通信的实体

一个程序的运行需要操作系统提供各种资源,比如CPU时间片,主存,IO设备等
应用程序都依赖操作系统,操作系统提供了应用程序运行时各种资源的管理分配以及维护
那么操作系统如何描述一个“程序的运行”?
进程就是操作系统对“程序的运行”进行抽象,对一个运行中的程序的描述
很多事物,当我们需要对他们进行识别管理时,最常用的方法就是编号,1号电脑,2号电脑;1号门,2号门等等
进程也不例外,进程ID(英语:processID)、PID)是大多数操作系统的内核用于唯一标识进程的一个数值。
所以说,在操作系统中,对于一个正在运行的程序,可是借助于进程ID---PID进行唯一标识。
因为计算机可以运行多个应用程序,所以,计算机的通信基本都是指应用程序间的通信
那么既然进程是一个程序运行的标识,就可以说是两个进程之间的通信

TCP/IP的应用

随着操作系统的发展,1983年,TCP/IP被Unix 4.2BSD系统采用。
随着Unix的成功,TCP/IP逐步成为Unix机器的标准网络协议。
也就是说操作系统内置了网络通信的功能,并且是按照TCP/IP协议实现的。
所谓的采用也就是用程序代码按照TCP/IP的逻辑实现了两个应用程序相互通信的功能
所以,在操作系统中谈论TCP/IP协议时,我们可以假想两个程序模块,一个TCP模块,一个IP模块,分别负责TCP和IP协议的实现
为了简单,甚至可以理解成就两个方法,一个叫tcp()一个叫ip()
tcp()接收到应用层的数据后,添加相应头部,然后交给ip(),添加ip相关头部。   

端口

通过一个IP地址就可以唯一的定位到一台主机,在通过进程号不就可以唯一确定一个应用程序么
但是事实恐怕不能如此,试想一下通信的过程
你说:“我希望和ip地址为xxx.xxx.xxx.xxx的主机的yyy进程进行通信”
想要通信自然要先知道ip地址,但是进程号是接收方操作系统对于接受信息的应用程序的描述,是操作系统内部的数据
而且,是动态分配的,就好像你一会儿叫张三,一会儿叫李四,我怎么跟你通信?
所以就出现了“端口”的概念,可以认为是计算机与外界通讯交流的出口
“端口”的概念将计算机进程与外界的联系进行解耦
比如21分配给ftp服务使用,外界想要使用该主机的ftp服务,只需要向21号端口发送请求即可,不需要关注提供ftp服务的应用程序的Pid
ftp服务程序只需要到21号这个窗口“接货”就好了
image_5c32c22f_3950
端口有三种类型
1.周知端口(Well Known Ports)
周知端口是众所周知的端口号,范围从0到1023
其中80端口分配给WWW服务,21端口分配给FTP服务等。
我们在IE的地址栏里输入一个网址的时候是不必指定端口号的,因为在默认情况下WWW服务的端口是“80”。
2.动态端口(Dynamic Ports)
动态端口的范围是从49152到65535。之所以称为动态端口,是因为它 一般不固定分配某种服务,而是动态分配。
3.注册端口
端口1024到49151,分配给用户进程或应用程序。
这些进程主要是用户选择安装的一些应用程序,而不是已经分配好了公认端口的常用程序。
这些端口在没有被服务器资源占用的时候,可以用用户端动态选用为源端口。
 
发起请求的客户端,不用关心自己的端口号,只需要将端口号告知接收端即可
但是客户端必须要知道接收端的端口号,这样才能与对方计算机的某一个应用程序进行通信。
所以说,一个计算机上的端口,是对外界打开的窗户。

操作系统的通信模型

说到这,了解了“进程、操作系统对TCP/IP的实现、端口”我们可以整理下操作系统对通信的处理逻辑:
一台计算机中会运行多个程序,我们使用进程的概念对程序进行标识,但是进程是计算机内部的标识,如何才能提供给外部?所以有了端口的概念,端口就相当于分机号。
而操作系统对于TCP/IP的实现,就是基于这样一种模式,实现了端到端的通信(也就是进程间的通信)
简单点说就是操作系统具备了端到端通信的功能,通过IP地址定位到主机,通过端口号定位到进程(某个运行中的应用程序)

socket编程接口

有了端口号和IP地址,我们就可以唯一的确定一台主机的一个应用程序了
那么, 也就是说有了这么一对“端口号和IP地址”
发送方的IP地址和端口号,以及接收方的IP地址和端口号,我们就可以通过网络进行通信
这就相当于一个精确到XXX小区XXX栋楼XXX号的一个地址,是通信过程中的两个端点,如同卖家的店铺和你的房子
这样一个端点,有一个有意思的名字,叫做socket 套接字
TCP协议就是提供端到端的通信
socket本意是插座,TCP协议将两个端点连接起来,即插即用,用插座来形容很形象
image_5c32c22f_4fbb
操作系统实现TCP/IP协议的目的是为了计算机通信,而计算机通信的目的也是为了计算机中的应用程序进行通信
如果没有任何的应用程序,那么计算机网络的意义也很小了
操作系统都会提供标准的编程接口,以供应用程序调用系统服务,操作系统对TCP/IP的实现也不例外,针对于操作系统实现的TCP/IP协议,也提供了对应的接口 ,以便应用程序可以借助于操作系统,实现网络互连 
这个编程接口API也叫做socket,所以,网络编程有时也被称为socket编程
socket是实现过程中,应用层程序和操作系统传输层程序的一个中间层,他并不属于网络协议的一部分
Socket 起源于Unix  WINDOWS下也有一套socket规范
socket是对TCP/IP协议的封装,复杂的TCP/IP协议族隐藏在Socket接口后面
它的出现使得程序员能够更加方便地借助于TCP/IP协议栈通信
想一下在平时的编码中,经常会出现这样一种情况:
对某些常用场景,将基础功能单元的方法进行进一步封装,提高使用的便利性
Socket 就相当于进一步封装后的方法
简言之,socket简化了使用TCP/IP的复杂程度。
 
一定程度上,可以将socket理解为外观模式(门面模式)
门面模式的意图:
“为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这一接口使得这一子系统更加易于使用。” 
image_5c32c22f_2352
 
从门面模式中应该能更容易理解,socket是实现层面上,应用层与传输层的中间层。   

总结

计算机网络将数据的传输进行分层,从而将复杂的问题进行简化
每一层仅仅关注当前层的交互逻辑,经理仅仅关注文件的签署情况
应用层仅仅关注应用之间的交流方式,运输层负责端到端的应用,网际层负责网络上两个主机之间的传输,链路层物理层负责将IP报文在物理设备上进行转发
  • 网际层和网络接口层(链路层和物理层)仅仅是负责转发,纯属送货的
  • 运输层相当于收发室,最后一步
  • 应用层才是目的地
通过计算机操作系统以及网络设备对协议的实现,最终构成了完整的计算机网络。
计算机实现了通信功能,并且提供了编程接口,所以对于程序员来说,一眼望过去只是socket编程接口,至于底层的复杂的TCP/IP的实现细节,完全不需要关注
插入socket这一编程接口层的目的也很显然,可以简化开发的复杂程度
本来很复杂的网络通信程序的设计与开发,经过层层的封装,转换成了只需要面向socket编程即可,比起前人,你是不是幸福太多?
参照上面网络数据在不同协议层之间的传输,有了socket,应用程序之间的网络通信编程,就只需要面向socket编程即可。
大大的降低了网络编程的成本,从socket API往下就如同不存在一样,这通常被叫做“透明”,透明的存在,比如一块高透的玻璃,看起来不就如同不存在一样么   
 
image_5c32c22f_3439
所以想要做一个合格的程序员,需要着眼于应用层和Socket接口层,想要成为一个优秀的程序员,需要对底层有一个更深入的了解。