我前面写的博客都是Linux系统相关的知识,再往前就是C++/C和数据结构的,这写也都写的差不多了,从这篇博客起就开始讲网络相关的知识了。
前面Linux部分的知识学起来比较枯燥,因为大多数人还没学网络之前都不知道学os到底能干啥,什么进程线程的,好像没什么用,这是因为没有数据来源,有了网络就可以从网络中接收数据,再让进程/线程来处理这些数据了,处理的时候有的线程用来读取IO,有的用来做计算,还有的用来连接数据库等等,所以当网络中有数据传来时,我们就要对其做系统级的处理,所以学习系统部分是学习网络的基础,我后面的博客讲讲网络,然后再让os和网络一结合,就可以写出网络级的代码了。
我前面也没写过网络的博客,所以本篇的知识不会涉及特别深,只是讲网络相关的一些名词、概念介绍介绍,讲讲其与系统的初步关系,关于网络的深度剖析后面的博客会再详谈。本篇的名词和概念有了就能简单的上手写一些网络相关的代码,带大家见见猪跑,能写出一些简单的客户端和服务端间通信的代码就行。
本篇重点讲解:
发展背景就简单介绍一下,这个对于新手来说了解了解还是很有必要的。
首先,是先有的计算机,然后才有的网络。(第一台计算机名字叫埃尼阿克,感兴趣的同学自行百度一下,我就不讲这个了)
后来,多台计算机可以连接在同一个服务器上:
当一个人处理完数据后可以再交给服务器,然后其他人可以从服务器上拿数据进行进一步的处理,处理完后还可再次发送。这里已经可以算是局域网了,比如早些年某些实验室,就是多台计算机连在一个服务器上。像什么贝尔实验室、伯克利的、麻省理工的等等。
但此时若两个实验室间有一个合作的项目,需要一块处理某些数据,就可以让两个局域网通过一个路由器连接,进行数据交互。这样局域网和局域网之间就可以进行通信了:
上面图中的交换机、路由器什么的稍后再简单讲讲,在后面深度讲网络的时候再详谈,本篇只是进行简单的扫盲。
可能各位的学校教材上还会有城域网的说法。
这里给小白解释解释,所谓的“局域网”、“城域网”、“广域网”只有规模上的差别,无非就是介入网络的主机个数不同,看一块网是哪个网在不同的视角下也是有一定的差异的。比如站在你们村子的角度来看,你家就可以看作局域网,整个村子的网络就可以看做是广域网,但是站在整个市或者整个省来看,你的村子又可看做是一个局域网,而整个城市才是一个广域网。
所以广域网什么的知识为了在学术上区分一下,但从技术角度,都是一些相对的概念,不过这里讲解的时候还是要说一说的。
我们生活中的这些网络是由谁建设和维护的呢?
答案是运营商,像移动、联通、电信啥的。
还有一个和运营商关系非常密切的,叫生产商,后者负责硬件上的支持,像华为、诺基亚等公司负责通信设备的生产。
有这两个角色各位才能看到手机上的B站、淘宝等APP,若有没有这两个角色为基础,那么就不可能存在什么APP,若有一方没做好就会出现问题,比如若运营商没做好网络方面的维护,网速很慢,各位刷CSDN的时候特别卡,半天才蹦出来一个页面,那这就很痛苦,相应的顾客就会减少。
网络中一个很重要的东西叫做协议。
啥是协议呢?
像我们买车 / 买房 / 工作的时候签合同,这就算是协议。
而在我们网络中,协议是指软硬件都要遵守的一种约定,用于在计算机网络中传输数据和进行通信。
网络中传输的数据是有类别的,有的数据只是一个普通的数据,比如说某人的姓名、性别等,而有的数据可以控制对方主机的操作等等,也就是说数据也是有其内容和属性的,就像文件一样有其内容和属性。
为了让两个相隔千里的主机能够快速的区分出数据是什么类别,每种类别中的特定内容又代表着什么含义,就要提前让这两台电脑约定好不同内容代表何种信息,这样就能减少双方通信带来的成本。那么这里的约定就可以说是协议。
不知屏幕前的你看过姜文的《让子弹飞》没,其中有一个场景就是张麻子一伙人去“剿匪”,他们在“剿匪”时通过吹哨来进行沟通,这就是一种通信方式。想要实现这种通信,就得让张麻子一伙的人都学会分辨出不同的哨声所代表的特定含义,并且还要会吹出代表着不同含义的哨声。
假如说吹两声短的就是全体进攻的意思(我瞎编的),两声长的就是撤退的意思(也是我瞎编的),这两声短和两声长的的哨声得让一伙人都得铭记在心,不同的声音对应不同的行为,这就是用哨子通信的协议。
来分析一下为什么要这么做?
减少成本。
如果有一句话非常长,而且打仗着嘞,你得吆喝着喊,不然可能队友听不见,但是吆喝着时间长了又容易暴露位置,敌人有可能发现你,有点危险,万一说之前气没喘上来中间又换了一口气,换气的时候有一个队友以为你说完了,而且还误解了你的意思,直接冲出去了,这不就会造成数据不一致问题么,那这个队友不就小命不保了么。而通过简短的哨声来发送数据,队友就能立马意识到该干什么事,你也不容易暴露。所以协议的设定能让双方通信更加高效。
只要通信的两台主机, 约定好协议就可以了么?
不是的,即便当两台主机约定好了协议单仍可能无法进行通信。计算机生产厂商有很多,计算机操作系统,也有很多,计算机网络硬件设备,还是有很多,如何让这些不同厂商之间生产的计算机能够相互顺畅的通信?就需要有人站出来,约定一个共同的软硬件标准,大家都来遵守, 这就是网络协议;
这就好像说方言一样,你让一个广东人和一个西藏人交流,西藏人说藏语,广东人说客家话,虽然都能表达出那个意思,但是讲出来是完全不一样的。虽然都是中国的,但对方都听不懂对方的语言。
说几点:
先不说协议被分成了哪几层,先来说说生活中现实场景分层的好处。
比如说两个人打电话:
在我们普通人看来,打电话时是两个人在直接通信,但是在技术人员的角度来看并不是这么简单,比如AB两方打电话,A方先和其电话交流,然后A方的电话再将A方人的信息经过一系列操作交给B方的电话,然后B方的电话再将收到的消息经过一系列操作交给B方的人。这里就有分层的体现,这里人有人的语言层,人和人用中文在沟通,而底层是两部电话在用电话能够识别的语言在通信,所以人打电话至少是两层通信的机制。
当两个老外打电话时,人和人的协议用的是盈余,但是并不会影响二者通信,底层还是用电话的协议。
当两个中国人用无线电沟通时,此时底层用的协议就变成了无线电的协议。
上面这个例子就能说说为啥要分层了。
网络协议是怎么分层的呢?
通过通信时出现的问题来分,不同层解决不同问题。
通信的复杂程度是和距离成正相关的。
单从通信范畴来说,千里之外的两个主机通信时可能出现的问题有:
上面三个问题,那么就可以有三层:
其实还会有一个问题,就是传输的时候用什么频率等硬件上的问题,这里的问题是物理层结局的,不过物理层太偏硬件了,我的博客中主要讲软件的内容,所以就不详细说物理层了。
还要从应用的范围来说,接收方在接收到数据后如何处理数据,这个问题由应用层来解决。所以共五层协议:
上面也说了,主要讲软件,所以物理层不做讨论,只关注上面四层:
这样的分层模型是最经典的网络协议分层模型——TCP/IP模型。
这里也分层了,那么网络协议的分层和这里的计算机的分层有什么关联吗?
答案是有的:
都是对应的。
后面博客中重点讲的是应用层的如何写,还有传输层和网络层的os怎么做。以后在进行通信的时候使用的是传输层向上提供的system call系统调用接口,所以网络编程的本质依旧是系统编程。因为用的依旧是os,故本质上依旧是在学os。
TCP(在传输层)/IP(在网络层)是在操作系统中实现的,主要完成通信细节的处理,上面的应用层是用户进程来完成的,主要处理应用程序处理数据的细节。
但定制标准网络协议的组织并不是严格按照上面的5层来搞得,而是7层:
这里的分层模型是OSI七层模型。比TCP/IP多了两层,一个叫表示层,一个叫会话层。
但是TCP/IP是在OSI之后才有的,二者的关系就像蓝图的实际建造的房子一样。
OSI只是由专业组织定义出来的,并不是他们实现出来的,在真正实现OSI的时候人们发现到应用程、表示层和会话层没法拆开,是一体的,所以就将三者合在一块了。
TCP/IP是一组协议的代名词,它还包括许多协议,组成了TCP/IP协议簇.
TCP/IP通讯协议采用了5层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求:
物理层我们考虑的比较少。因此很多时候也可以称为 TCP/IP四层模型。
一般而言
对于一台主机, 它的操作系统内核实现了从传输层到物理层的内容;
对于一台路由器, 它实现了从网络层到物理层;
对于一台交换机, 它实现了从数据链路层到物理层;
对于集线器, 它只实现了物理层;
但是并不绝对. 很多交换机也实现了网络层的转发; 很多路由器也实现了部分传输层的内容(比如端口转发)。
物理层: 负责光/电信号的传递方式。
比如现在以太网通用的网线(双绞线)、早期以太网采用的的同轴电缆(现在主要用于有线电视)、光纤, 现在的wifi无线网使用电磁波等都属于物理层的概念。物理层的能力决定了最大传输速率、传输距离、抗干扰性等. 集线器(Hub)工作在物理层.
数据链路层: 负责设备之间的数据帧的传送和识别。
例如网卡设备的驱动、帧同步(就是说从网线上检测到什么信号算作新帧的开始)、冲突检测(如果检测到冲突就自动重发)、数据差错校验等工作. 有以太网、令牌环网, 无线LAN等标准. 交换机(Switch)工作在数据链路层.
网络层: 负责地址管理和路由选择。
例如在IP协议中, 通过IP地址来标识一台主机, 并通过路由表的方式规划出两台主机之间的数据传输的线路(路由). 路由器(Router)工作在网路层.
传输层: 负责两台主机之间的数据传输。
如传输控制协议 (TCP), 能够确保数据可靠的从源主机发送到目标主机.
应用层: 负责应用程序间沟通。
如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等. 我们的网络编程主要就是针对应用层
在同一个局域网中的两台主机是可以直接通信的,通信时在逻辑上是当前主机的应用层直接将数据传给了另一台主机的应用层:
但是实际上并不是,就像刚刚打电话的那个例子一样。
通信时,一方的数据必须先自顶向下将数据报文从应用层传递到最下面,然后再通过局域网(下面的那个以太网就是应用最广泛的局域网)传递到另一方的链路层,然后再自底向上传到应用层:
w
为啥要这样干呢,我来讲一个生活中的例子。
假如你和你朋友住在同一个小区,但是你俩不在同一栋楼中,你在A楼,TA在B楼,但是你俩都在第五层,如果你朋友想要给你送一个礼物,这时候TA得从B楼的第五层下到第一层,然后再通过AB楼间的路走到A的楼下,然后再跑到A的五层,此时就送到你手上了。所以逻辑上来说是你朋友把礼物直接送到了你手中,但是从物理方面来说,TA是先从上到下,然后再经过中间的路,然后再从下到上把礼物送过来的。就和这里的数据传输一样。一个是从用户的角度去理解,一个是从工程师的角度去理解。
层状结构中,每一层都有自己的协议定制方案,每层协议都要有自己的协议报头,从上到下传递数据的时候要添加报头,从下到上递交数据时要去掉报头,比如说我现在QQ发了一个你好,整个向下传输的流程大致就是这样的:
向上传输时每一层都会进行解包,解包就是将自己得到的数据的报头和有效载荷(有效载荷就是每一层最外层长方形框出来的东西)分离,并将有效载荷交给上层,就是这样:
那报头是干啥的呢?
想想各位寄快递和取快递的时候,寄快递时需要填一张单子,那张单子就贴在你的递上,这张快递并不是给寄件人或收件人看的,而是给快递公司看的,这里的快递单就可以看作是报头,对于寄取双方并没有什么作用,就是一个多出来的东西,寄 ==》快递公司 ==》快递公司 ==》收件人,一共是两层。收到快递进行解包,解包后拿到数据即交付,不过说只有两层,解包的工作是自己一个人干的。
上层向下传递数据时,下层要根据自身协议来为上层传下来的数据添加某些字段,而另一方的同层在接收到数据时也要根据其协议来为下层传上来的数据中的相应字段做解析和处理。协议报头就是收到的报文当中多出来的数据内容。报头能够决定交给上层的哪一个协议。
自上到下封装:添加报头。
自下到上解包:去掉报头 + 展开分析(后面说)。
添加报头类似于入栈,解包类似于弹栈,这样同层在逻辑上就是在直接通信:
这样效率能更高一点,每一层不需要找报头在哪,直接找栈顶就行。
前面说了局域网中的两台主机可以直接通信,那么是怎么做到的呢?
先来讲个例子:
教室上课,老师点名张三回答问题,此时全班的同学动能听到,但只有张三一个人站起来了,二者对话时全班的人是都能听见的,但老师只是和张三在沟通,也即在所有人都能接受到信息时二者进行了定向通信,老师 ==》张三,张三 ==》老师。
问:为什么老师点名张三时,其他同学不站起来?(问题有点二)
因为老师没叫其他人,但这句话的前提是所有同学都收到了这个消息。
局域网就很类似,通信的时候就相当于某台主机在整个局域网中开麦,然后点名某个主机,就可以给那个主机发消息了。看图:
此时有ABCDEF六台主机连在同一个局域网中,当B想和E通信时,B发数据前会点名要把这个数据发给E,但是点名的时候ACDEF都可以听见,不过他们都会先对比一下B主机叫的D主机名和自己的主机名是否一样,发现不是在叫自己就会直接丢掉这个信息,所以最终只有D接收到了这个数据,并将数据向上传递做后续处理,同样的D若想回B消息,也是同样的原理。
当上课时,有一门捣蛋分子不断打断老师上课节奏,课就没法上了。在整个教室这个介质中,所有的人都可以说话,当老师上课时,有同学在不断发出很大的噪音,就会影响老师的发言,也就会影响老师和其他学生的通信。
同样B和E主机通信时,是通过局域网这个介质来通信的,而局域网中,只要连上的主机就可以往局域网中发送光电信号,若此时A主机在BE联系的正欢的时候随便发消息,这样就会导致BE发送的和A发送的光电信号混合在一块,这样B和D的信息就识别不了了,这就叫做局域网内数据通信时发生了碰撞问题。
在不同局域网中的主机通信的时候稍微有点不一样,不过加报头和去报头的流程还是一样的。
不同的局域网种类可能是不同的。注意我加粗了可能,目前最流行的局域网类型有以太网和无线局域网。
如果各位想看看局域网有哪些可以看看这篇博客:局域网有哪些种类?目前流行哪几类局域网?。
当不同的局域网(种类可能相同也可能不同)想要通信的时候要通过路由器,前面最开始的那几张发展历史的图也说了。
想要讲一下详细流程的话得先说说两个地址:MAC地址和IP地址。
MAC地址是数据链路层用的,IP地址是网络层用的。
先来说说IP地址和MAC地址都是干啥的,举个例子:
西游记应该都看过吧,唐僧应该都知道吧。就拿唐僧来说。
唐僧从头到尾在别人问他从哪来到哪去时,他总是说的是“贫僧从东土大唐而来,到西天拜佛求经”。这一路上他就要干这个,源头到目的地永远不会改变,一直是东土大唐(源头)到西天(目的地)。
假如唐僧是个路痴,每到一个地就得问一个人下一站往哪走。假设此时唐僧师徒四人在碧波潭已经把万圣龙王给端了,此时他问路人去西天要往哪走时,路人给他说往荆棘岭走,唐僧一行人就屁颠屁颠的往荆棘岭去,然后通关荆棘岭后又在荆棘岭问路人该去哪时,路人说去七绝山,然后四人又去七绝山了。至此,就可以说说IP地址和MAC地址了。
这里唐僧身上有两套地址。
.
IP地址就是从头到尾一直不变的东土大唐 ==》西天,那么东土大唐就是源IP,西天就是目的IP。IP地址从头到尾一直不变。但是IP地址可以为唐僧从当前站到下一站往哪走提供方向。
.
MAC地址是会随着唐僧所在位置的变化而变化的,唐僧在碧波潭时,下一站要往荆棘岭走,此时的出发地是碧波潭,目的地是荆棘岭,那么这里的源MAC地址就是碧波潭,目的MAC地址就是荆棘岭。而当唐僧跑到荆棘岭后,下一站要往七绝山去,那么此时源MAC地址就是荆棘岭,目的MAC地址就是七绝山。每次的目的MAC地址都是受目的IP(西天)影响的,不能说唐僧要去西边,下一站的MAC地址跑到了东边的高老庄。
- 唐僧在取经时,源IP和目的IP永不变。每次经过一个地方就相当于数据经过了一台路由器,问路人西天怎么走时路人会为唐僧回答下一站在哪,这个过程就叫做路由,那么路由的本质就是根据数据的目的地选择下一站去哪里。
MAC地址能够表示局域网中某一主机的唯一性。
IP地址在整个互联网中是唯一的。
能听出来区别不,MAC的唯一性是局部的,而IP的唯一是全局的。
在局域网中,MAC地址是指网络设备(如计算机、路由器、交换机等)所拥有的唯一标识符。MAC地址由48位二进制数字组成,通常用十六进制表示。每个网络设备的MAC地址都是唯一的,这是通过设备制造商在生产过程中分配给每个设备的。
看上面的MAC地址,一共六个字节,也就是48位,用十六进制表示,一个十六进制数字能表示4位,那么就会有12个十六进制数,两两一块,人家都给你分好了。这里的地址就是以太网地址,前面的那个单词ether就有以太的意思。俗称MAC地址。
MAC地址的唯一性保证了在局域网中不会出现重复的地址,这样可以确保数据包能够正确地从源设备传输到目标设备。当设备在局域网上发送数据包时,它将目标设备的MAC地址包含在数据包的头部,这样交换机或路由器就能根据MAC地址将数据包传送到正确的设备。
尽管MAC地址在局域网中是唯一的,但它只在局域网范围内具有唯一性。当数据包离开局域网并经过路由器进入广域网时,源设备的MAC地址将被替换为路由器的MAC地址。
再来看图:
这里的inet为IPnet的简写,代表主机的IP地址,云服务器上该IP为内网IP,我们平时用的是公网IP。
关于公网IP和内网IP的区别可以看这篇:什么是公网IP?公网IP与内网IP的区别?。
IP协议有两个版本, IPv4和IPv6. 我们整个的课程, 凡是提到IP协议, 没有特殊说明的, 默认都是指IPv4
IP地址是在IP协议中, 用来标识网络中不同主机的地址;
对于IPv4来说, IP地址是一个4字节, 32位的整数;
我们通常也使用 “点分十进制” 的字符串表示IP地址, 例如 192.168.0.1 ; 用点分割的每一个数字表示一个字节, 范围是 0 - 255;
图中有两个局域网通过路由器连在一起了。
此时A向B发送数据,还是先从上到下添加报头,但是不能直接通过A所在局域网发给B所在的局域网了,要先把A的数据发给路由器,然后再由路由器发给B所在的局域网(令牌环网),此时再从下到上解包给主机B。
同样的操作,不过中间多了几步,而且这几步非常重要。
封装时网络侧(也就是图中IP的那一层)会将源IP和目的IP(源IP就是A主机的IP,目的主机就是B主机的IP)封装到该层的报头中。
而数据链路层会将源MAC地址和目的MAC地址(此处的源MAC地址就是A主机的MAC地址,目的MAC地址就是路由器的MAC地址)封装到该层的报头中。
此时最重要的几步开始了,封装好的数据会通过以太网发送到路由器那个虚线长方形中的以太网驱动程序,也就是数据链路层,而这一步就根据的是数据包中数据链路层的报头中的源MAC和目的MAC:
并在此处对数据链路层的数据的报头和有效载荷分开,去掉报头就是去掉其原来数据的源MAC地址和目标MAC地址,并将有效载荷传给路由器的网络层:
此时路由器网络层接收到数据时一看数据的源IP和目的IP,说我知道B主机在哪,下一站你往右边的那个局域网走就行,所以此时数据继续从路由器的网络层去往数据链路层,然后添加报头,添加报头时用的是令牌环网的报头,源MAC地址就变成了路由器的MAC,目的MAC地址就变成了B主机的MAC:
各位有没有发现,在整个流程中数据只有数据链路层时是不一样的,而网络层以上的层都是一样的:
同层拿到的都是一个数据,所以可以说,无论两台主机跨了多远,在网络层网上的同层看到的数据都是一样的。只有底层是稍有差异的。
所以整个TCP/IP协议的网络流程中,IP及其以上的协议,看到的报文都是一样的。
我就画两个就行了,多个同理。数据传输的大致流程就是这样。中间不断更新源MAC地址和目的MAC地址。
到这就讲的差不多了,再来点专业术语。
不同的协议层对数据有不同的称谓,在传输层叫做数据段(segment),在网络层叫做数据报 (datagram),在链路层叫做数据帧(frame)。其实都是数据,叫法不同罢了,我上面讲解时就同一用数据来说了。
应用层数据通过协议栈发到网络上时,每层协议都要加上一个数据首部(header),称为封装(Encapsulation)。就是添加报头。
首部信息中包含了一些类似于首部有多长, 有效载荷(payload)有多长, 上层协议是什么等信息.
数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部, 根据首部中的 “上层协议字段” 将数据交给对应的上层协议处理。也就是解包。
上面图中的以太网尾部帧是以太网数据帧的最后一个字段,它的作用是提供错误检测和纠正功能,以确保数据的完整性。尾部帧通常由4个字节的FCS(Frame Check Sequence)组成,它是通过对数据帧中的所有比特进行计算得到的校验值。接收方可以使用FCS值来检测数据传输过程中是否发生了错误,并且在检测到错误时可以丢弃该数据帧。
我前面也讲了,首部还决定了将当前的数据交给上层的哪个协议,这里就体现出了这一点。这里图中网络层有三个协议IP、ARP、RARP,传输层有四个:TCP、UDP、ICMP、IGMP,当然不止这么些, 这里不讲那么深入了,等后面博客再详谈。只要记住当前层解包后的有效载荷要交给上层的那个协议是有当前层的报头决定的。发送方同层用的是哪个协议都会写在报头中,所以交付的时候就会对应交给的协议。
除去掉最上层的应用层,每一层的协议都要考虑数据如何解包问题。就像各位小时候上课传小纸条一样,你写一个小纸条要传给你朋友,别人不能看,只能由规定的人看(也就是你朋友),如果非常机密的话,中间被人看到了,你很生气下课直接给偷看的人揍了一顿,开个玩笑,就是为了让屏幕前你记住有效载荷由上层的固定协议来拿。
到此结束。。。