文章首发于我的bloghtml
欢迎指正补充,可联系lionsom_lin@qq.comgit
原文地址:《网络是怎样链接的》阅读整理程序员
检查您的网络链接github
查看网络路由表和统计数据web
测试 DNS 服务器浏览器
为何会读这本书?做为一名普通的iOS开发者,在iOS开发过程当中通常使用三方库AFNetworking来进行网络请求,不多使用到系统的网络请求接口NSURLSession,顶多顶多使用过socket套接字进行网络请求,这里是我用socket与FastDFS文件服务器进行交互的一个demo。因此咱们做为上层开发者通常只会使用规定好的接口,根本不会在乎网络请求底层是如何实现或者说是如何传递数据的,基于这种状况,我也就很好奇网络请求底层是如何如何的。bash
因而我也就在亚马逊上挑选了这本《网络是怎样链接的》书籍来进行阅读,但愿能从中获得些许启发,借此文章来记录一些我对网络的理解。
http://www.baidu.com
a)、http://www.baidu.com/dir/
在
/dir/
后面省略了访问的文件名,服务器已经默认设置在省略文件名状况下要访问的默认文件名,通常都会访问/dir/index.html
或者/dir/default.html
。
b)、http://www.baidu.com/dir
通常处理方案:若是web服务器上存在dir文件,则将dir看成文件名来处理;若是web服务器上存在名为dir的目录,则将dir看成目录来处理。
c)、http://www.baidu.com/
这个URL表示:它访问一个名叫
/
的目录。因为省略了文件名,因此根据上一种状况,它访问的文件也就是/index.html
或者/default.html
。 注释:/
目录表示的是目录层级中最顶级的『根目录』。
d)、http://www.baidu.com
没有路径时,表示访问
根目录
下事先设置的默认文件夹,也就是/index.html
或者/default.html
。
HTTP协议:它定义了客户端与服务器之间交互信息的内容和步骤
HTTP请求消息包含『对什么』和『进行怎样的操做』两个部分。 其中至关于『对什么』的部分称为URI。通常来讲URI的内容是一个存放网页的文件名或者是一个CGI程序的文件名,例如"/dir/file.html"、"/dir/program.cgi"等。 其中『进行怎样的操做』的部分称为方法。方法表示须要让web服务器完成怎样的工做,其中典型的例子包括读取URI表示的数据、将客户端输入的数据传递给CGI程序等。
URI:Uniform Resource Identifier,统一资源标识符
CGI程序:对web服务器程序调用其余程序的规则所作的定义就是CGI,安装这个规则来工做的程序就是CGI程序。
HTTP的主要方法
方法 | 含义 |
---|---|
GET | 获取URI指定的信息,若是URI指定的文件,则返回文件的内容;若是URI指定的是CGI程序,则返回该程序的输出数据 |
POST | 从客户端向服务器发送数据。通常用于发送表单中填写的数据等状况下。 |
HTTP消息在格式上是有严格规定的,所以浏览器会按照规定的格式来生成请求消息。
响应状态码
1条请求消息中只能写一个URI,若是须要获取多个文件,必须对每一个文件单独发送1条请求
浏览器可以解析网址并生成HTTP消息,但它自己不具有将消息发送到网络的功能,所以这一功能须要委托操做系统来实现。在委托操做系统发送消息时,必须提供通信对象的IP地址,而不是域名,所以在HTTP消息以后,咱们须要根据域名查询IP地址。
互联网和公司内部的局域网都是基于TCP/IP的思路来设计的,TCP/IP的结构就是由一些小的子网,经过路由器链接起来组成一个大的网络,这里的子网能够理解为用集线器链接起来的几台计算机,咱们将它当作一个单位,称为子网,将子网经过路由器链接起来,就造成一个网络。
在网络中,全部的设备都会被分配一个地址,这个地址就至关于显示中某一条路上的"XX号XX室",其中"号"对应的号码是分配给整个子网的,而"室"对应的号码是分配给子网中的计算机的,这就是网络中的地址。"号"称为网络号,"室"称为主机号,整个地址称为
IP地址
。IP地址 = 网络号 + 主机号
预热:数据传递过程
经过IP地址咱们能够判断出访问对象服务器的位置,从而将消息发送到服务器。消息传送的具体过程在后面的章节有详细讲解,不过如今咱们先简单了解一下。发送者发出的消息首先通过子网中的集线器,转发到距离发送者最近的路由器上(上图①)。接下来,路由器会根据消息的目的地判断下一个路由器的位置,而后将消息发送到下一个路由器,即消息再次通过子网内的集线器被转发到下一个路由器(上图②)。前面的过程不断重复,最终消息就被传送到了目的地。
实际的IP地址是一串32比特(bit)的数字,按照8bit=1byte(字节)为一组分红4组,分别用十进制表示。这就是咱们常见的IP地址格式,但仅凭这一串数字咱们没法区分哪部分是网络号,哪部分是主机号。在IP地址的规则中,网络号和主机号连起来总共是32比特,但这两部分的具体结构是不固定的。在组建网络时,用户能够自行决定它们之间的分配关系,所以,咱们还须要另外的附加信息来表示IP地址的内部结构。
IP地址的主机号:
全0:表示
整个子网
全1:表示向子网上全部设备发送包,即
『广播』
【拓展】
问:有了 IP 地址,为何还要用 MAC 地址?
DNS解析器
向 DNS服务器发出查询,也就是向DNS服务器发送查询消息,并接收服务器返回的响应消息。换句话说,对于 DNS服务器,咱们的计算机上必定有相应的 DNS客户端,而至关于 DNS客户端的部分称为
DNS解析器
,或者简称解析器
。经过 DNS查询 IP地址的操做称为域名解析
,所以负责执行解析( resolution)这一操做的就叫解析器( resolver)了。解析器其实是一段程序,它包含在操做系统的 Socket库中。
库
首先,库究竟是什么东西呢?库就是一堆通用程序组件的集合,其余的应用程序都须要使用其中的组件。库有不少好处。首先,使用现成的组件搭建应用程序能够节省编程工做量;其次,多个程序使用相同的组件能够实现程序的标准化。除此以外还有不少其余的好处,所以使用库来进行软件开发的思路已经很是普及,库的种类和数量也很是之多。
Socket库
Socket库也是一种库,是用于调用网络功能的程序组件集合。其中包含的程序组件可让其余的应用程序调用操做系统的网络功能 ,而
解析器
就是这个库中的其中一种程序组件。
根据域名查询 IP地址时,浏览器会使用 Socket库中的解析器。
调用解析器后,解析器会向 DNS服务器发送查询消息,而后DNS服务器会返回响应消息。响应消息中包含查询到的IP地址,解析器会取出 IP地址,并将其写入浏览器指定的内存地址中。只要运行图 1.11中的这一行程序,就能够完成前面全部这些工做,咱们也就完成了IP地址的查询。接下来,浏览器在向 Web服务器发送消息时,只要从该内存地址取出 IP地址,并将它与HTTP请求消息一块儿交给操做系统就能够了。
向 DNS服务器发送消息时,咱们固然也须要知道 DNS服务器的 IP地址。只不过这个 IP地址是做为 TCP/ IP的一个设置项目事先设置好的,不须要再去查询了。不一样的操做系统中 TCP/ IP的设置方法也有差别, MAC中的设置以下图所示,解析器会根据这里设置的 DNS服务器 IP地址来发送消息。
DNS服务器会从域名与 IP地址的对照表中查找相应的记录,并返回 IP地址。
域名
例如:www.baidu.com
服务器、邮件服务器(邮件地址中 @后面的部分)的名称
Class
在最先设计 DNS方案时, DNS在互联网之外的其余网络中的应用也被考虑到了,而 Class就是用来识别网络的信息。不过,现在除了互联网并无其余的网络了,所以 Class的值永远是表明互联网的 IN
记录类型
例如:A = IP地址
MX = 邮件服务器
CNAME = 域名相关的别名
表示域名对应何种类型的记录。例如,当类型为 A时,表示域名对应的是 IP地址;当类型为 MX时,表示域名对应的是邮件服务器。对于不一样的记录类型,服务器向客户端返回的信息也会不一样
域名层次结构
DNS中的域名都是用句点来分隔的,好比 www.lab.glasscom.com,这里的句点表明了不一样层次之间的界限,就至关于公司里面的组织结构不用部、科之类的名称来划分,只是用句点来分隔而已 。
在域名中,越靠右的位置表示其层级越高
,好比 www. lab. glasscom. com这个域名若是按照公司里的组织结构来讲,大概就是“ com事业集团 glasscom部 lab科的 www”这样。其中,至关于一个层级的部分称为域。所以, com域的下一层是 glasscom域,再下一层是 lab域,再下面才是 www这个名字。
根域
com、jp、cn这些域(称为顶级域)就是最顶层了,它们各自负责保存下级DNS服务器的信息,但实际上并不是如此。在互联网中,com和 jp的上面还有一级域,称为根域。根域不像 com、 jp那样有本身的名字,所以在通常书写域名时常常被省略,若是要明确表示根域,应该像 www. lab. glasscom. com.这样在域名的最后再加上一个句点,而这个最后的句点就表明根域。不过,通常都不写最后那个句点,所以根域的存在每每被忽略,但根域毕竟是真实存在的,根域的 DNS服务器中保管着 com、 jp等的 DNS服务器的信息。因为上级 DNS服务器保管着全部下级 DNS服务器的信息,因此咱们能够从根域开始一路往下顺藤摸瓜找到任意一个域的 DNS服务器。
经过根域找到目标DNS服务器
还须要完成另外一项工做,那就是将根域的 DNS服务器信息保存在互联网中全部的 DNS服务器中。这样一来,任何 DNS服务器就均可以找到并访问根域 DNS服务器了。所以,客户端只要可以找到任意一台 DNS服务器,就能够经过它找到根域 DNS服务器,而后再一路顺藤摸瓜找到位于下层的某台目标 DNS服务器。分配给根域 DNS服务器的 IP地址在全世界仅有 13个,并且这些地址几乎不发生变化,所以将这些地址保存在全部的 DNS服务器中也并非一件难事。实际上,根域 DNS服务器的相关信息已经包含在 DNS服务器程序的配置文件中了,所以只要安装了 DNS服务器程序,这些信息也就被自动配置好了。
<描述符> = socket(<使用IPv4>,<使用TCP>,...)
浏览器调用Socket库中socket程序组件,和调用解析器同样,调用socket以后,控制流程会转移到socket内部并执行建立套接字的操做,完成以后控制流程又会被移交回应用程序。
应用程序调用 socket申请建立套接字,协议栈根据应用程序的申请执行建立套接字的操做。在这个过程当中,协议栈首先会分配用于存放一个套接字所需的内存空间,而后写入初始状态。此内存空间用于记录套接字的控制信息。
套接字 建立成功后,协议栈会返回一个描述符,应用程序会将收到的描述符存放在内存中。
描述符
应用程序是经过“描述符”这一类 似号码牌的东西来识别套接字的。
描述符是用来识别不一样的套接字的,你们能够做以下理解。咱们如今只关注了浏览器访问 Web服务器的过程,但实际上计算机中会同时进行多个数据的通讯操做,好比能够打开两个浏览器窗口,同时访问两台 Web服务器。这时,有两个数据收发操做在同时进行,也就须要建立两个不一样的套接字。这个例子说明,同一台计算机上可能同时存在多个套接字,在这样的状况下,咱们就须要一种方法来识别出某个特定的套接字,这种方法就是描述符。咱们能够将描述符理解成给某个套接字分配的编号。也许光说编号还不够形象,你们能够想象一下在酒店寄存行李时的场景,酒店服务人员会给你一个号码牌,向服务人员出示号码牌,就能够取回本身寄存的行李,描述符的原理和这个差很少。当建立套接字后,咱们就可使用这个套接字来执行收发数据的操做了。这时,只要咱们出示描述符,协议栈就可以判断出咱们但愿用哪个套接字来链接或者收发数据了。
因为套接字中记录了通讯双方的信息以及通讯处于怎样的状态,因此只要经过描述符肯定了相应的套接字,协议栈就可以获取全部的相关信息,这样一来,应用程序就不须要每次都告诉协议栈应该和谁进行通讯了。
套接字
socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员作网络开发所用的接口,这就是Socket编程接口。
套接字是网络通讯过程当中端点的抽象表示,包含进行网络通讯必需的五种信息:链接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
socket = IP address + TCP/UDP + port。
协议栈
操做系统中的网络控制软件也就是协议栈,网络硬件是网卡。
套接字与协议栈之间的关系
套接字中记录了用于控制通讯操做的各类控制信息,协议栈则须要根据这些信息判断下一步的行动,这就是套接字的做用。
协议栈是根据套接字中记录的控制信息来工做的。
OSI七层网络模型(Open System Interconnect) | TCP/IP网络模型 | 对应网络协议 |
---|---|---|
应用层(Application) | HTTP、FTP、TFTP、SMTP、NFS | |
表示层(Presentation) | 应用层 | |
会话层(Session) | SMTP、DNS | |
传输层(Transport) | 传输层 | TCP、UDP |
网络层(Network) | 网络层 | IP、ARP、ICMP |
数据链路层(Data Link) | 数据链路层 | |
物理层(Physical) | 物理层 |
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr* servaddr, socklen_t addrlen); // 返回:成功为0,出错-1
复制代码
应用程序经过调用 Socket库中的名为 connect的程序组件来完成这一操做。
第一个参数:即描述符,connect会将应用程序指定的描述符告知协议栈,而后协议栈根据这个描述符来判断到底使用哪个套接字去和服务器端的套接字进行链接,并执行链接的操做
第二个参数,即服务器 IP地址,就是经过 DNS服务器查询获得的咱们要访问的服务器的 IP地址。
第三个参数,即端口号,IP地址是为了区分网络中的各个计算机而分配的数值。所以,只要知道了 IP地址,咱们就能够识别出网络上的某台计算机。可是,链接操做的对象是某个具体的套接字,所以必需要识别到具体的套接字才行,而仅凭IP地址是没法作到这一点的。
若是说描述符是用来在一台计算机内部识别套接字的机制,那么端口号就是用来让通讯的另外一方可以识别出套接字的机制。
服务器上所使用的端口号是根据应用的种类事先规定好的,仅此而已。
Web是 80号端口,电子邮件是 25号端口 65
问题:咱们知道了服务器的端口号,可是服务器不知道客户端的端口号?
既然肯定链接对象的套接字须要使用端口号,那么服务器也得知道客户端的套接字号码才行吧,这个问题是怎么解决的呢?
事情是这样的,首先,客户端在建立套接字时,协议栈会为这个套接字随便分配一个端口号。接下来,当协议栈执行链接操做时,会将这个随便分配的端口号通知给服务器。
链接服务器本质
链接其实是通讯双方交换控制信息
控制信息
通讯操做中使用的控制信息分为两类。
(1)头部中记录的信息
(2)套接字(协议栈中的内存空间)中记录的信息
控制信息一:头部中记录的信息
他们是客户端和服务器相互联络时交换的控制信息。这些字段是固定的,在链接、收发、断开等各个阶段中,每次客户端和服务器之间进行通讯时,都须要提供这些控制信息。具体来讲,这些信息会被添加在客户端与服务器之间传递的网络包的开头。在链接阶段,因为数据收发尚未开始,网络包中没有实际的数据,只有控制信息。这些控制信息位于网络包的开头,所以被称为头部。此外,以太网和IP协议也有本身的控制信息,这些信息也叫 头部,为了不各类不一样的头部发生混淆,咱们通常会记做 TCP头部、以太网头部、 IP头部。
控制信息二:套接字(协议栈中的内存空间)中记录的信息
那就是保存在套接字中,用来控制协议栈操做的信息。应用程序传递来的信息以及从通讯对象接收到的信息都会保存在这里,还有收发数据操做的执行状态等信息也会保存在这里,协议栈会根据这些信息来执行每一步的操做。
这个过程是从应用程序调用 Socket库的connect开始的(看上图『总体流程一览图』中②)。 >
connect(<描述符>,<服务器IP地址和端口号>, …)
链接操做的第一步是在 TCP模块处建立表示链接控制信息的头部。
经过 TCP头部中的发送方和接收方端口号能够找到要链接的套接字。
从图中能够看出,当客户端调用connect时,触发了链接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到链接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1以后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,链接创建。
创建链接以后,协议栈的链接操做就结束了,也就是说 connect已经执行完毕,控制流程被交回到应用程序。
接下来就进入数据收发阶段了。数据收发操做是从应用程序调用 write将要发送的数据交给协议栈开始的(看上图『总体流程一览图』中③),协议栈收到数据后执行发送操做。
MTU: Maximum Transmission Unit,最大传输单元。一个网络包的最大长度,以太网中通常为 1500字节。
MSS: Maximum Segment Size,最大分段大小。除去头部以后,一个网络包所能容纳的 TCP数据的最大长度。TCP和 IP的头部加起来通常是 40字节,所以 MTU减去这个长度就是 MSS。例如,在以太网中, MTU为 1500,所以 MSS就是 1460。 TCP/ IP可使用一些可选参数( protocol option),如加密等,这时头部的长度会增长,那么 MSS就会随着头部长度增长而相应缩短。
应用程序的数据通常都比较大,所以 TCP会按照网络包的大小对数据进行拆分。
经过“序号”和“ ACK号”能够确认接收方是否收到了网络包。
首先,浏览器在委托协议栈发送请求消息以后,会调用read程序(看上图『总体流程一览图』中④)来获取响应消息。而后,控制流程会经过read转移到协议栈,而后协议栈会执行接下来 的操做。和发送数据同样,接收数据也须要将数据暂存到接收缓冲区中,这里的操做过程以下。首先,协议栈尝试从接收缓冲区中取出数据并传递给应用程序,但这个时候请求消息刚刚发送出去,响应消息可能还没返回。响应消息的返回还须要等待一段时间,所以这时接收缓冲区中并无数据,那么接收数据的操做也就没法继续。这时,协议栈会将应用程序的委托,也就是从接收缓冲区中取出数据并传递给应用程序的工做暂时挂起,等服务器返回的响应消息到达以后再继续执行接收操做。
协议栈会检查收到的数据块和 TCP头部的内容,判断是否有数据丢失,若是没有问题则返回 ACK号。而后,协议栈将数据块暂存到接收缓冲区中,并将数据块按顺序链接起来还原出原始的数据,最后将数据交给应用程序。具体来讲,协议栈会将接收到的数据复制到应用程序指定的内存地址中,而后将控制流程交回应用程序。将数据交给应用程序以后,协议栈还须要找到合适的时机向发送方发送窗口更新。
这里咱们以服务器一方发起断开过程为例来进行讲解。
首先,服务器一方的应用程序会调用Socket库的close程序。而后,服务器的协议栈会生成包含断开信息的 TCP头部,具体来讲就是将控制位中的 FIN比特设为 1。接下来,协议栈会委托 IP模块向客户端发送数据。同时,服务器的套接字中也会记录下断开操做的相关信息。
和服务器的通讯结束以后,用来通讯的套接字也就不会再使用了,这时咱们就能够删除这个套接字了。不过,套接字并不会当即被删除,而是会等待一段时间以后再被删除。等待这段时间是为了防止误操做。
误操做举例:若是最后客户端返回的 ACK号丢失了,结果会如何呢?这时,服务器没有接收到 ACK号,可能会重发一次 FIN。若是这时客户端的套接字已经删除了,会发生什么事呢?套接字被删除,那么套接字中保存的控制信息也就跟着消失了,套接字对应的端口号就会被释放出来。这时,若是别的应用程序要建立套接字,新套接字碰巧又被分配了同一个端口号,而服务器重发的 FIN正好到达,会怎么样呢?原本这个 FIN是要发给刚刚删除的那个套接字的,但新套接字具备相同的端口号,因而这个 FIN就会错误地跑到新套接字里面,新套接字就开始执行断开操做了。之因此不立刻删除套接字,就是为了防止这样的误操做。
TCP模块在执行链接、收发、断开等各阶段操做时,都须要委托 IP模块将数据封装成包发送给通讯对象。咱们在 TCP的讲解中也常常提到 IP,下面就来讨论一下 IP模块是如何将包发送给对方的。
正式开始这个话题以前,咱们先来介绍一下关于网络包的一些基本知识。首先,包是由头部和数据两部分构成的(下图(a))。头部包含目的地址等控制信息,你们能够把它理解为快递包裹的面单;头部后面就是委托方要发送给对方的数据,也就至关于快递包裹里的货物。一个包发往目的地的过程如图 2. 15所示。
收到委托后, IP模块会将包的内容看成一整块数据,在前面加上包含控制信息的头部。
IP模块负责添加以下两个头部:
(1)IP头部: IP用的头部,包含 IP地址。IP头部中包含 IP协议规定的、根据 IP地址将包发往目的地所需的控制信息;
(2)MAC头部:以太网用的头部,包含 MAC地址。MAC头部包含经过以太网的局域网将包传输至最近的路由器所需的控制信息。
总之,加上这两个头部以后,一个包就封装好了,这些就是 IP模块负责的工做。
返回的包也会经过转发设备发送回来,而后咱们须要接收这个包。接收的过程和发送的过程是相反的,信息先以电信号的形式从网线传输进来,而后由网卡将其转换为数字信息并传递给 IP模块(下图中的“ ③接收”)。接下来, IP模块会将 MAC头部和 IP头部后面的内容,也就是 TCP头部加上数据块,传递给 TCP模块。接下来的操做就是咱们以前讲过的 TCP模块负责的部分了。
IP头部的“接收方 IP地址”填写通讯对象的 IP地址。
发送方 IP地址须要判断发送所使用的网卡,并填写该网卡的 IP地址。
不少服务器上都会安装多块网卡,这时一台计算机就有多个 IP地址,在填写发送方 IP地址时就须要判断到底应该填写哪一个地址。这个判断至关于在多块网卡中判断应该使用哪一块网卡来发送这个包,也就至关于判断应该把包发往哪一个路由器,所以只要肯定了目标路由器,也就肯定了应该使用哪块网卡,也就肯定了发送方的 IP地址。
那么,咱们应该如何判断应该把包交给哪块网卡呢?其实和路由器使用 IP表(也叫路由表)判断下一个路由器位置的操做是同样的。由于协议栈的 IP模块与路由器中负责包收发的部分都是根据 IP协议规则来进行包收发操做的,因此它们也都用相同的方法来判断把包发送给谁。
(路由器收发下一章节具体说)
发送方 MAC地址,这里填写网卡自己的 MAC地址。 MAC地址是在网卡生产时写入 ROM里的,只要将这个值读取出来写入 MAC头部就能够了。对于多块网卡的状况,请你们回想一下设置发送方 IP地址的方法 。设置发送方 IP地址时,咱们已经判断出了从哪块网卡发送这个包,那么如今只要将这块网卡对应的 MAC地址填进去就行了。
只要告诉以太网对方的 MAC的地址,以太网就会帮咱们把包发送过去,那么很显然这里应该填写对方的 MAC地址。然而,在这个时间点上,咱们尚未把包发送出去,因此先得搞清楚应该把包发给谁,这个只要查一下路由表就知道了。在路由表中找到相匹配的条目,而后把包发给 Gateway列中的 IP地址就能够了。既然已经知道了包应该发给谁,那么只要将对方的 MAC地址填上去就行了,但到这里为止根本没有出现对方的 MAC地址,也就是说咱们如今根本不知道对方的 MAC地址是什么。所以,咱们还须要执行根据 IP地址查询 MAC地址的操做。详情看 4.4.一、经过 ARP查询目标路由器的 MAC地址
IP模块根据路由表 Gateway栏的内容判断应该把包发送给谁。
这里咱们须要使用 ARP协议(网络层协议),它其实很是简单。在以太网中,有一种叫做广播的方法,能够把包发给链接在同一以太网中的全部设备。 ARP就是利用广播对全部设备提问:“ × ×这个 IP地址是谁的?请把你的 MAC地址告诉我。”而后就会有人回答:“这个 IP地址是个人,个人 MAC地址是 × × × ×。” (下图)
ARP: Address Resolution Protocol,地址解析协议。
经过ARP缓存提高效率,避免每次发送
MAC: Media Access Control的缩写。 MAC头部、 MAC地址中的 MAC也是这个意思。也就是说,经过 MAC模块控制包收发操做时所使用的头部和地址就叫做 MAC头部和 MAC地址。
IP生成的网络包只是存放在内存中的一串数字信息,没有办法直接发送给对方。所以,咱们须要将数字信息转换为电或光信号,才能在网线上传输,也就是说,这才是真正的数据发送过程。负责执行这一操做的是网卡,但网卡也没法单独工做,要控制网卡还须要网卡驱动程序。驱动程序不仅有网卡才有,键盘、鼠标、显卡、声卡等各类硬件设备都有。固然,不一样厂商和型号的网卡在结构上有所不一样,所以网卡驱动程序也是厂商开发的专用程序。
网卡的 ROM中保存着全世界惟一的 MAC地址,这是在生产网卡时写入的。
网卡驱动从 IP模块获取包以后,会将其复制到网卡内的缓冲区中,而后向 MAC模块发送发送包的命令。接下来就轮到 MAC模块进行工做了。首先, MAC模块会将包从缓冲区中取出,并在开头加上报头和起始帧分界符,在末尾加上用于检测错误的帧校验序列
网卡MAC模块将包从缓冲区中取出,并在开头加上 报头 和 起始帧分界符,在末尾加上用于检测错误的 帧校验序列。
报头是一串像 10101010…这样 1和 0交替出现的比特序列,长度为 56比特,它的做用是肯定包的读取时机。当这些 1010的比特序列被转换成电信号后,会造成如图这样的波形。接收方在收到信号时,遇到这样的波形就能够判断读取数据的时机。
用电信号来表达数字信息时,咱们须要让 0和 1两种比特分别对应特定的电压和电流,例以下图( a)这样的电信号就能够表达数字信息。经过电信号来读取数据的过程就是将这种对应关系颠倒过来。也就是说,经过测量信号中的电压和电流变化,还原出 0和 1两种比特的值。然而,实际的信号并不像下图所示的那样有分隔每一个比特的辅助线,所以在测量电压和电流时必须先判断出每一个比特的界限在哪里。可是,像下图( a)右边这种 1和 0连续出现的信号,因为电压和电流没有变化,咱们就没办法判断出其中每一个比特到底应该从哪里去切分。
要解决这个问题,最简单的方法就是在数据信号以外再发送一组用来区分比特间隔的时钟信号。如图( b)所示,当时钟信号从下往上变化时读取电压和电流的值,而后和 0或 1进行对应就能够了。可是这种方法存在问题。当距离较远,网线较长时,两条线路的长度会发生差别,数据信号和时钟信号的传输会产生时间差,时钟就会发生偏移。
另一种方法是当时钟信号从上往下变化时进行读取。要解决这个问题,能够采用将数据信号和时钟信号叠加在一块儿的方法。这样的信号如图( c)所示,发送方将这样的信号发给接收方。因为时钟信号是像图( b)这样按固定频率进行变化的,只要可以找到这个变化的周期,就能够从接收到的信号( c)中提取出时钟信号( b),进而经过接收信号( c)和时钟信号( b)计算出数据信号( a),这和发送方将数据信号和时钟信号进行叠加的过程正好相反。而后,只要根据时钟信号( b)的变化周期,咱们就能够从数据信号( a)中读取相应的电压和电流值,并将其还原为 0或 1的比特了。
起始帧分界符,它的末尾比特排列有少量变化。接收方以这一变化做为标记,从这里开始提取网络包数据。也就是说,起始帧分界符是一个用来表示包起始位置的标记。
末尾的 FCS(帧校验序列)用来检查包传输过程当中因噪声致使的波形紊乱、数据错误,它是一串 32比特的序列,是经过一个公式对包中从头至尾的全部内容进行计算而得出来的。具体的计算公式在此省略,它和磁盘等设备中使用的 CRC错误校验码是同一种东西,当原始数据中某一个比特发生变化时,计算出来的结果就会发生变化。在包传输过程当中,若是受到噪声的干扰而致使其中的数据发生了变化,那么接收方计算出的 FCS和发送方计算出的 FCS就会不一样,这样咱们就能够判断出数据有没有错误。
网卡的 MAC模块生成通用信号,而后由 PHY( MAU)模块转换成可在网线中传输的格式,并经过网线发送出去。
接收操做的第一步就是无论三七二十一把这些信号全都收进来再说。信号的开头是报头,经过报头的波形同步时钟,而后遇到起始帧分界符时开始将后面的信号转换成数字信息。这个操做和发送时是相反的,即 PHY( MAU)模块先开始工做,而后再轮到 MAC模块。首先, PHY( MAU)模块会将信号转换成通用格式并发送给 MAC模块, MAC模块再从头开始将信号转换为数字信息,并存放到缓冲区中。当到达信号的末尾时,还须要检查 FCS。具体来讲,就是将从包开头到结尾的全部比特套用到公式中计算出 FCS,而后和包末尾的 FCS进行对比,正常状况下二者应该是一致的,若是中途受到噪声干扰而致使波形发生紊乱,则二者的值会产生差别,这时这个包就会被看成错误包而被丢弃。若是 FCS校验没有问题,接下来就要看一下 MAC头部中接收方 MAC地址与网卡在初始化时分配给本身的 MAC地址是否一致,以判断这个包是否是发给本身的。咱们不必去接收发给别人的包,所以若是不是本身的包就直接丢弃,若是接收方 MAC地址和本身 MAC地址一致,则将包放入缓冲区中 。到这里, MAC模块的工做就完成了,接下来网卡会通知计算机收到了一个包。
通知计算机的操做会使用一个叫做中断的机制。在网卡执行接收包的操做的过程当中,计算机并非一直监控着网卡的活动,而是去继续执行其余的任务。所以,若是网卡不通知计算机,计算机是不知道包已经收到了这件事的。网卡驱动也是在计算机中运行的一个程序,所以它也不知道包到达的状态。在这种状况下,咱们须要一种机制可以打断计算机正在执行的任务,让计算机注意到网卡中发生的事情,这种机制就是中断。具体来讲,中断的工做过程是这样的。首先,网卡向扩展总线中的中断信号线发送信号,该信号线经过计算机中的中断控制器链接到 CPU。当产生中断信号时, CPU会暂时挂起正在处理的任务,切换到操做系统中的中断处理程序 。而后,中断处理程序会调用网卡驱动,控制网卡执行相应的接收操做。
网卡驱动被中断处理程序调用后,会从网卡的缓冲区中取出收到的包,并经过 MAC头部中的以太类型字段判断协议的类型。如今咱们在大多数状况下都是使用 TCP/ IP协议,但除了 TCP/ IP以外还有不少其余类型的协议,例如 NetWare中使用的 IPX/ SPX,以及 Mac电脑中使用的 AppleTalk等协议。这些协议都被分配了不一样的以太类型,如 0080(十六进制)表明 IP协议,网卡驱动就会把这样的包交给 TCP/ IP协议栈;若是是 809B则表示 AppleTalk协议,就把包交给 AppleTalk协议栈,以此类推。
下面咱们假设 Web服务器返回了一个网络包,那么协议栈会进行哪些处理呢 100?服务器返回的包的以太类型应该是 0800,所以网卡驱动会将其交给 TCP/ IP协议栈来进行处理。接下来就轮到 IP模块先开始工做了,第一步是检查 IP头部,确认格式是否正确。若是格式没有问题,下一步就是查看接收方 IP地址。若是接收网络包的设备是一台 Windows客户端计算机,那么服务器返回的包的接收方 IP地址应该与客户端网卡的地址一致,检查确认以后咱们就能够接收这个包了。
若是接收方 IP地址不是本身的地址,那必定是发生了什么错误。客户端计算机不负责对包进行转发,所以不该该收到不是发给本身的包 101。当发生这样的错误时, IP模块会经过 ICMP消息将错误告知发送方(图 2. 1)。 ICMP规定了各类类型的消息,如表所示。当咱们遇到这个错误时, IP模块会经过表中的 Destination unreachable消息通知对方。从这张表的内容中咱们能够看到在包的接收和转发过程当中可以遇到的各类错误,所以但愿你们看一看这张表。
若是接收方 IP地址正确,则这个包会被接收下来,这时还须要完成另外一项工做。 IP协议有一个叫做分片的功能。简单来讲,网线和局域网中只能传输小包,所以须要将大的包切分红多个小包。若是接收到的包是通过分片的,那么 IP模块会将它们还原成原始的包。分片的包会在 IP头部的标志字段中进行标记,当收到分片的包时, IP模块会将其暂存在内部的内存空间中,而后等待 IP头部中具备相同 ID的包所有到达,这是由于同一个包的全部分片都具备相同的 ID。此外, IP头部还有一个分片偏移量( fragment offset)字段,它表示当前分片在整个包中所处的位置。根据这些信息,在全部分片所有收到以后,就能够将它们还原成原始的包,这个操做叫做分片重组。
接下来包会被交给 TCP模块。 TCP模块会根据 IP头部中的接收方和发送方 IP地址,以及 TCP头部中的接收方和发送方端口号来查找对应的套接字。找到对应的套接字以后,就能够根据套接字中记录的通讯状态,执行相应的操做了。例如,若是包的内容是应用程序数据,则返回确认接收的包,并将数据放入缓冲区,等待应用程序
(1)路由器根据目标地址判断下一个路由器的位置
(2)集线器在子网中将网络包传输到下一个路由
实际上,集线器是按照以太网规则传输包的设备,而路由器是按照 IP规则传输包的设备,所以咱们也能够做以下理解。
(1)IP协议根据目标地址判断下一个 IP转发设备的位置
(2)子网中的以太网协议将包传输到下一个转发设备
场景设定:网络包在进入互联网以前经历的传输过程。这里咱们假设客户端计算机链接的局域网结构是像下图这样的。也就是说,网络包从客户端计算机发出以后,要通过集线器、交换机和路由器最终进入互联网。实际上,咱们家里用的路由器已经集成了集线器和交换机的功能,像图上这样使用独立设备的状况不多见。
网卡 -> 网线 -> 集线器
从信号流出网卡进入网线开始。网卡中的 PHY( MAU) 2模块负责将包转换成电信号,信号经过 RJ-45接口进入双绞线,这部分的放大图以下图的右侧部分所示。以太网信号的本质是正负变化的电压,你们能够认为网卡的 PHY( MAU)模块就是一个从正负两个信号端子输出信号的电路。
信号在网线的传输过程当中,能量会逐渐损失。网线越长,信号衰减就越严重。集线器收到的信号有时会出现衰减。以下图。
局域网网线使用的是双绞线,其中“双绞”的意思就是以两根信号线为一组缠绕在一块儿,这种拧麻花同样的设计是为了抑制噪声的影响。
首先,咱们来看看噪声是如何产生的。产生噪声的缘由是网线周围的电磁波,当电磁波接触到金属等导体时,在其中就会产生电流。所以,若是网线周围存在电磁波,就会在网线中产生和本来的信号不一样的电流。因为信号自己也是一种带有电压变化的电流,其本质和噪声产生的电流是同样的,因此信号和噪声的电流就会混杂在一块儿,致使信号的波形发生失真,这就是噪声的影响。
影响网线的电磁波分为两种:
一种是由电机、荧光灯、 CRT显示器等设备泄漏出来的电磁波,这种电磁波来自网线以外的其余设备,
另外一种电磁波是从网线中相邻的信号线泄漏出来的。因为传输的信号自己就是一种电流,当电流流过期就会向周围发出电磁波,这些电磁波对于其余信号线来讲就成了噪声。这种内部产生的噪声称为串扰( crosstalk)。
a)经过两根信号线的缠绕抵消外源性噪声;
b)经过改变节距抑制内源性噪声。
集线器的做用?
集线器将信号发送给全部链接在它上面的线路。
信号到达集线器的 PHY( MAU)模块后,会进入中继电路。中继电路的基本功能就是将输入的信号广播到集线器的全部端口上。固然,也有一些产品具备信号整形、错误抑制等功能,但基本上就是将输入的信号原封不动地输出到网线接口。接下来,信号从全部接口流出,到达链接在集线器上的全部设备。而后,这些设备在收到信号以后会经过 MAC头部中的接收方 MAC地址判断是否是发给本身的,若是是发给本身的就接受,不然就忽略。这样,网络包就可以到达指定 MAC地址的接收方了。
因为集线器只是原封不动地将信号广播出去,因此即使信号受到噪声的干扰发生了失真,也会原样发送到目的地。这时,接收信号的设备,也就是交换机、路由器、服务器等,会在将信号转换成数字信息后经过 FCS8校验发现错误,并将出错的包丢弃。固然,丢弃包并不会影响数据的传输,由于丢弃的包不会触发确认响应。所以协议栈的 TCP模块会检测到丢包,并对该包进行重传。
你们只要看明白路由器包括转发模块和端口模块两部分就能够了。其中转发模块负责判断包的转发目的地,端口模块负责包的收发操做。换句话说,路由器转发模块和端口模块的关系,就至关于协议栈的 IP模块和网卡之间的关系。
路由器的各个端口都具备 MAC地址和 IP地址。
路由器在转发包时,首先会经过端口将发过来的包接收进来,这一步的工做过程取决于端口对应的通讯技术。对于以太网端口来讲,就是按照以太网规范进行工做,而无线局域网端口则按照无线局域网的规范工做,总之就是委托端口的硬件将包接收进来。接下来,转发模块会根据接收到的包的 IP头部中记录的接收方 IP地址,在路由表中进行查询,以此判断转发目标。而后,转发模块将包转移到转发目标对应的端口,端口再按照硬件的规则将包发送出去,也就是转发模块委托端口模块将包发送出去的意思。
交换机是经过 MAC头部中的接收方 MAC地址来判断转发目标的,而路由器则是根据 IP头部中的 IP地址来判断的。
交换机在地址表中只匹配彻底一致的记录,而 路由器则会忽略主机号部分,只匹配网络号部分。打个比方,路由器在转发包的时候只看接收方地址属于哪一个区, × ×区发往这一边, × ×区发往那一边。
路由器的整个工做过程。首先,路由器会接收网络包。路由器的端口有各类不一样的类型,这里咱们只介绍以太网端口是如何接收包的。以太网端口的结构和计算机的网卡基本相同,接收包并存放到缓冲区中的过程也和网卡几乎没有区别。首先,信号到达网线接口部分,其中的 PHY( MAU)模块和 MAC模块将信号转换为数字信息,而后经过包末尾的 FCS进行错误校验,若是没问题则检查 MAC头部中的接收方 MAC地址,看看是否是发给本身的包,若是是就放到接收缓冲区中,不然就丢弃这个包。若是包的接收方 MAC地址不是本身,说明这个包是发给其余设备的,若是接收这个包就违反了以太网的规则。
路由器的端口都具备 MAC地址,只接收与自身地址匹配的包,遇到不匹配的包则直接丢弃。
完成包接收操做以后,路由器就会丢弃包开头的 MAC头部。 MAC头部的做用就是将包送达路由器,其中的接收方 MAC地址就是路由器端口的 MAC地址。所以,当包到达路由器以后, MAC头部的任务就完成了,因而 MAC头部就会被丢弃。
经过路由器转发的网络包,其接收方 MAC地址为路由器端口的 MAC地址。
关于具体的工做过程,咱们仍是来看一个实际的例子,如上图的状况,假设地址为 10. 10. 1. 101的计算机要向地址为 192. 168. 1. 10的服务器发送一个包,这个包先到达图中的路由器。判断转发目标的第一步,就是根据包的接收方 IP地址查询路由表中的目标地址栏,以找到相匹配的记录。就像前面讲过的同样,这个匹配并非匹配所有 32个比特,而是根据子网掩码列中的值判断网络号的比特数,并匹配相应数量的比特 33。例如,上图的第 3行,子网掩码列为 255. 255. 255. 0,就表示须要匹配从左起 24个比特。网络包的接收方 IP地址和路由表中的目标地址左起 24个比特的内容都是 192. 168. 1,所以二者是匹配的,该行记录就是候选转发目标之一。
这一步操做取决于输出端口的类型。若是是以太网端口,则按照以太网的规则将包转换为电信号发送出去;若是是 ADSL则按照 ADSL的规则来转换,以此类推。在家庭网络中,路由器后面通常链接 ADSL等线路接入互联网,所以路由器会根据接入网的规则来发送包。不过,要理解具体的操做过程,须要先理解相应的通讯线路 ,比较复杂,所以咱们留到下一章探索互联网内部时再讲解。这里,咱们假设路由器位于公司等局域网的内部,即输出端口也是以太网,看看这种状况是如何操做的。
以太网的包发送操做是根据以太网规则来进行的,即使设备种类不一样,规则也是相同的。也就是说,其基本过程和协议栈中的 IP模块发送包的过程是相同的,即在包前面加上 MAC头部,
设置其中的一些字段,而后将完成的包转换成电信号并发送出去。下面来简单复习一下这个过程。首先,为了判断 MAC头部中的 MAC地址应该填写什么值,咱们须要根据路由表的网关列判断对方的地址。若是网关是一个 IP地址,则这个 IP地址就是咱们要转发到的目标地址;若是网关为空,则 IP头部中的接收方 IP地址就是要转发到的目标地址。知道对方的 IP地址以后,接下来须要经过 ARP根据 IP地址查询 MAC地址,并将查询的结果做为接收方 MAC地址。路由器也有 ARP缓存,所以首先会在 ARP缓存中查询,若是找不到则发送 ARP查询请求。
路由器判断下一个转发目标的方法以下。
- 若是路由表的网关列内容为 IP地址,则该地址就是下一个转发目标。
- 若是路由表的网关列内容为空,则 IP头部中的接收方 IP地址就是下一个转发目标。
路由器也会使用 ARP来查询下一个转发目标的 MAC地址。
网络包完成后,接下来会将其转换成电信号并经过端口发送出去。这一步的工做过程和计算机也是相同的。例如,当以太网工做在半双工模式时,须要先确认线路中没有其余信号后才能发送,若是检测到碰撞,则须要等待一段时间后重发。若是以太网工做在全双工模式,则不须要确认线路中的信号,能够直接发送。若是输出端口为以太网,则发送出去的网络包会经过交换机到达下一个路由器。因为接收方 MAC地址就是下一个路由器的地址,因此交换机会根据这一地址将包传输到下一个路由器。接下来,下一个路由器会将包转发给再下一个路由器,通过层层转发以后,网络包就到达了最终的目的地。
IP协议自己没有传输包的功能,所以包的实际传输要委托以太网来进行。
路由器是基于 IP设计的,而交换机是基于以太网设计的,所以 IP与以太网的关系也就是路由器与交换机的关系。换句话说,路由器将包的传输工做委托给交换机来进行
IP(路由器)负责将包送达通讯对象这一总体过程,而其中将包传输到下一个路由器的过程则是由以太网(交换机)来负责的。
此章节没啥好说的,了解下便可!
防火墙的基本思路,即只容许发往特定服务器中的特定应用程序的包经过,而后屏蔽其余的包。
包过滤方式的防火墙可根据接收方 IP地址、发送方 IP地址、接收方端口号、发送方端口号、控制位等信息来判断是否容许某个包经过。
防火墙没法抵御的攻击
防火墙能够根据包的起点和终点来判断是否容许其经过,但仅凭起点和终点并不能筛选出全部有风险的包。
好比,假设 Web服务器在收到含有特定数据的包时会引发宕机。可是防火墙只关心包的起点和终点,所以即使包中含有特定数据,防火墙也没法发现,因而包就被放行了。而后,当包到达 Web服务器时,就会引起服务器宕机。经过这个例子你们能够看出,只有检查包的内容才能识别这种风险,所以防火墙对这种状况无能为力。
a)方法一:这个问题的根源在于 Web服务器程序的 Bug,所以修复 Bug防止宕机就是其中一种方法。这类 Bug中,危险性较高的会做为安全漏洞公布出来,开发者会很快发布修复了 Bug的新版本,所以持续关注安全漏洞信息并更新软件的版本是很是重要的。
b)另外一种方法就是在防火墙以外部署用来检查包的内容并阻止有害包的设备或软件。
使用多台服务器来分担负载的方法更有效。这种架构统称为分布式架构。
最简单的一种是经过 DNS服务器来分配。当访问服务器时,客户端须要先向 DNS服务器查询服务器的 IP地址,若是在 DNS服务器中填写多个名称相同的记录,则每次查询时 DNS服务器都会按顺序返回不一样的 IP地址。
DNS轮询不足之处
例如:假如多台 Web服务器中有一台出现了故障,这时咱们但愿在返回 IP地址时可以跳过故障的 Web服务器,然而普通的 DNS服务器并不能确认 Web服务器是否正常工做,所以即使 Web服务器宕机了,它依然可能会返回这台服务器的 IP地址。
根据缓存服务器分布第三种方式,进行布局。
网卡的 MAC模块将网络包从信号还原为数字信息,校验 FCS并存入缓冲区。
在这个过程当中,服务器的 CPU并非一直在监控网络包的到达,而是在执行其余的任务,所以 CPU并不知道此时网络包已经到达了。但接下来的接收操做须要 CPU来参与,所以网卡须要经过 中断 将网络包到达的事件通知给 CPU。接下来, CPU就会暂停当前的工做,并切换到网卡的任务。而后,网卡驱动会开始运行,从网卡缓冲区中将接收到的包读取出来,根据 MAC头部的以太类型字段判断协议的种类,并调用负责处理该协议的软件。这里,以太类型的值应该是表示 IP协议,所以会调用 TCP/ IP协议栈,并将包转交给它。
网卡驱动会根据 MAC头部判断协议类型,并将包交给相应的协议栈。
( 1)IP模块首先会检查 IP头部的格式是否符合规范,而后检查接收方 IP地址,看包是否是发给本身的;
( 2)判断网络包是否通过分片;
( 3)须要检查 IP头部的协议号字段,并将包转交给相应的模块。例如,若是协议号为 06(十六进制),则将包转交给 TCP模块;若是是 11(十六进制),则转交给 UDP模块。
第一步:当 TCP头部中的控制位 SYN为 1时,表示这是一个发起链接的包。这时, TCP模块会执行接受链接的操做,不过在此以前,须要先检查包的接收方端口号,并确认在该端口上有没有与接收方端口号相同且正在处于等待链接状态的套接字。若是指定端口号没有等待链接的套接字,则向客户端返回错误通知的包。向客户端返回一个表示接收方端口不存在等待链接的套接字的 ICMP消息。
第二步:若是存在等待链接的套接字,则为这个套接字复制一个新的副本,并将发送方 IP地址、端口号、序号初始值、窗口大小等必要的参数写入这个套接字中,同时分配用于发送缓冲区和接收缓冲区的内存空间。而后生成表明接收确认的 ACK号,用于从服务器向客户端发送数据的序号初始值,表示接收缓冲区剩余容量的窗口大小,并用这些信息生成 TCP头部,委托 IP模块发送给客户端。
第三步:这个包到达客户端以后,客户端会返回表示接收确认的 ACK号,当这个 ACK号返回服务器后,链接操做就完成了。这时,服务器端的程序应该进入调用 accept的暂停状态,当将新套接字的描述符转交给服务器程序以后,服务器程序就会恢复运行。
( 1)收到数据包时, TCP模块会根据收到的包的发送方 IP地址、发送方端口号、接收方 IP地址、接收方端口号找到相对应的套接字;
( 2)将数据块拼合起来并保存在接收缓冲区中;
( 3)向客户端返回 ACK。
在TCP协议的规则中,断开操做能够由客户端或服务器任何一方发起,具体的顺序是由应用层协议决定的。Web中,这一顺序随HTTP协议版本不一样而不一样,在HTTP1.0中,是服务器先发起断开操做。
(1)服务器会调用Socket库的socket,TCP模块会生成一个 FIN为 1的 TCP头部,并委托 IP模块发送给客户端
(2)当客户端收到这个包后,会返回一个ACK号,
(3)接下来客户端会调用close,生成一个 FIN为 1的 TCP头部发给服务器,
(4)服务器再返回一个 ACK号。