《网络是怎么连接的》读书笔记-第1章 浏览器生成消息

《网络是怎么连接的》读书笔记

点击这里浏览全书目录。

第1章 浏览器生成消息——探索浏览器内部

1.1 生成HTTP请求消息

1.1.1 输入网址(URL)

http://www.baidu.com

除了http:,网址还可以以其他一些文字开头,例如ftp:file:mailto:等。

举例 “file:” 如下:

可以选择txt、pdf、png等常见格式文件,选择用浏览器打开,查看网址栏内容即可。

在这里插入图片描述

在这里插入图片描述

1.1.2 浏览器解析URL

在这里插入图片描述
在这里插入图片描述

1.1.3 省略文件名的情况

  • http://www.lab.glasscom.com/dir/

以“/”结尾代表/dir/后面本来应该有的文件名被省略了,该请求会访问服务器上事先设置好文件名,大多数情况下是index.html或者default.htm之类的文件名。

  • http://www.lab.glasscom.com/

该URL访问一个名叫“/”的目录。由于省略了文件名,所以结果就是访问/index.html或者/default.htm这样的文件。

  • http://www.lab.glasscom.com

当没有路径名时,就代表访问根目录下事先设置的默认文件,也就是/index. html或者/default.htm这些文件。

  • http://www.lab.glasscom.com/whatisthis

如果Web服务器上存在名为whatisthis的文件,则将whatisthis作为文件名来处理;如果存在名为whatisthis的目录,则将whatisthis作为目录名来处理。

1.1.4 HTTP的基本思路

HTTP协议定义了客户端和服务器之间交互的消息内容和步骤。

在这里插入图片描述

客户端会向服务器发送请求消息,其中包含的内容是“对什么”“进行怎样的操作”两个部分。

“对什么”:该部分称为URI。一般来说,URI的内容是一个存放网页数据的文件名或者是一个CGI程序的文件名,例如“/dir1/file1.html”、“/dir1/program1.cgi”等。

“进行怎样的操作”:该部分称为方法。表示需要让Web服务器完成怎样的工作,其中典型的例子包括读取URI表示的数据、将客户端输入的数据发送给URI表示的程序等。

URI:Uniform Resource Identifier,统一资源标识符。一般是一个存放网页数据的文件名或者是一个CGI程序的文件名,例如“/dir1/file1.html”、“/dir1/program1.cgi”等

CGI:对web服务器程序调用其他程序的规则所做的定义就是CGI,安装这个规则来工作的程序就是CGI程序。

HTTP的主要方法如下:最常用的方法为GETPOST

在这里插入图片描述

○:在该版本的规格中定义的项目。

△:并非正式规格,而是在规格书附录(Appendix)中定义的附加功能。

Web服务器在收到请求消息之后,会对其中的内容进行解析,通过URI和方法来判断“对什么”“进行怎样的操作”,并根据这些要求来完成自己的工作,然后将结果存放在响应消息中。

在响应消息的开头有一个状态码,它用来表示操作的执行结果是成功还是发生了错误。状态码后面就是头字段和网页数据。响应消息会被发送回客户端,客户端收到之后,浏览器会从消息中读出所需的数据并显示在屏幕上。

1.1.5 生成HTTP请求消息

浏览器对URL进行解析之后,确定了Web服务器和文件名,下面将会根据这些信息生成HTTP请求信息。

HTTP消息是有严格的格式规定的。

在这里插入图片描述

1.1.6 发送请求后会收到响应

响应消息的格式以及基本思路和请求消息是相同的,差别只在第一行上。

在响应消息中,第一行的内容为状态码和响应短语,用来表示请求的执行结果是成功还是出错。

在这里插入图片描述

每条请求消息中只能写1个URI,所以每次只能获取1个文件,如果需要获取多个文件,必须对每个文件单独发送1条请求。

比如1个网页中包含1张图片,那么获取网页加上获取图片,一共需要向Web服务器发送2条请求,而Web服务器却毫不知情,它完全不关心这2条请求获取的文件到底是1个网页上的还是不同网页上的,它的任务就是对每一条单独的请求返回1条响应而已。

在这里插入图片描述
在这里插入图片描述

1.2 向DNS服务器查询Web服务器的IP地址

生成HTTP消息之后,接下来我们需要委托操作系统将消息发送给Web服务器。尽管浏览器能够解析网址并生成HTTP消息,但它本身并不具备将消息发送到网络中的功能,因此这一功能需要委托操作系统来实现。

在进行这一操作时,我们需要查询网址中服务器域名对应的IP地址。在委托操作系统发送消息时,必须要提供的不是通信对象的域名,而是它的IP地址。

1.2.1 IP地址的基本知识

互联网和公司内部的局域网都是基于TCP/IP的思路来设计的,所以我们先来了解TCP/IP的基本思路。

TCP/IP的结构如下图所示,就是由一些小的子网,通过路由器连接起来组成一个大的网络。这里的子网可以理解为用集线器连接起来的几台计算机,我们将它看作一个单位,称为子网。将子网通过路由器连接起来,就形成了一个网络。

在这里插入图片描述

在网络中,所有的设备都会被分配一个地址。这个地址就相当于现实中某条路上的“××号××室”。其中“号”对应的号码是分配给整个子网的,而“室”对应的号码是分配给子网中的计算机的,也就是说,“号”对应的号码称为网络号,“室”对应的号码称为主机号,这个地址的整体称为IP地址。

IP地址 = 网络号 + 主机号

通过IP地址我们可以判断出访问对象服务器的位置,从而将消息发送到服务器。发送者发出的消息首先经过子网中的集线器,转发到距离发送者最近的路由器上(上图①)。接下来,路由器会根据消息的目的地判断下一个路由器的位置,然后将消息发送到下一个路由器,即消息再次经过子网内的集线器被转发到下一个路由器(上图②)。前面的过程不断重复,最终消息就被传送到了目的地。

IP地址和子网掩码

网络号和主机号连起来总共是32比特,但这两部分的具体结构是不固定的。

在组建网络时,用户可以自行决定它们之间的分配关系,因此我们还需要另外的附加信息来表示IP地址的内部结构,即子网掩码。

子网掩码是一串与IP地址长度相同的32比特数字,其左边一半都是1,右边一半都是0。子网掩码为1的部分表示网络号,为0的部分表示主机号

在这里插入图片描述

将子网掩码按照和IP地址一样的方式以每8比特为单位用圆点分组后写在IP地址的右侧,这就是下图(b)的方法。这种写法太长,我们也可以把1的部分的比特数用十进制表示并写在IP地址的右侧,如下图(c)所示。这两种方式只是写法上的区别,含义是完全一样的。

在这里插入图片描述

注:

主机号部分的比特全部为0或者全部为1时代表两种特殊的含义。

主机号意义
全0表示整个子网
全1表示向子网上所有设备发送包,即“广播”

1.2.2 域名和IP地址并用的理由

TCP/IP网络是通过IP地址来确定通信对象的,因此不知道IP地址就无法将消息发送给对方,这和我们打电话的时候必须要知道对方的电话号码是一个道理。因此,在委托操作系统发送消息时,必须要先查询好对方的IP地址。

  1. 为什么在网址中写服务器名字不直接写IP地址?

人性化,相较于一串数字组成的IP地址,服务器名称更好记。

  1. 为什么不直接用服务器名称确定通信对象?

IP地址的长度为32比特,也就是4字节,相对地,域名最短也要几十个字节,最长甚至可以达到255字节。这增加了路由器的负担,传送数据也会花费更长的时间。

  1. 当下方案是人使用服务器名称,路由器使用IP地址,二者之间关系问题怎么解决?

DNS:Domain Name System,域名服务系统。将服务器名称和IP地址进行关联是其常见用法,其它功能可以自行了解。

1.2.3 Socket库提供查询IP地址功能(DNS解析器)

库就是一堆通用程序组件的集合,其他的应用程序都需要使用其中的组件。使用现成的组件搭建应用程序可以节省编程工作量;多个程序使用相同的组件可以实现程序的标准化。除此之外还有很多其他的好处,因此使用库来进行软件开发的思路已经非常普及,库的种类和数量也非常之多。

  • Socket库

用于调用网络功能的程序集合。其包含的程序组件可以让其他的应用程序调用操作系统的网络功能。

  • DNS解析器

向DNS服务器发出查询,并接收服务器返回的响应消息。换句话说,对于DNS服务器,我们的计算机上一定有相应的DNS客户端,而相当于DNS客户端的部分称为DNS解析器,或者简称解析器。通过DNS查询IP地址的操作称为域名解析,因此负责执行解析(resolution)这一操作的就叫解析器(resolver)。
解析器实际上就是一段程序,它包含在操作系统的Socket库中。

1.2.4 通过解析器向DNS服务器发出查询

Socket库中的程序都是标准组件,在使用解析器时只要从应用程序中进行调用即可。

在这里插入图片描述

浏览器在向Web服务器发送消息时,只要从该内存地址(由应用程序指定)取出IP地址,并将它与HTTP请求消息一起交给操作系统即可。

1.2.5 解析器的内部原理

在这里插入图片描述

当控制流程转移到解析器后,解析器会生成要发送给DNS服务器的查询消息。

这个过程与浏览器生成要发送给Web服务器的HTTP请求消息的过程类似,解析器会根据DNS的规格,生成一条表示“请告诉我www.lab.glasscom.com的IP地址”的数据,并将它发送给DNS服务器(上图③)。

发送消息这个操作并不是由解析器自身来执行,而是要委托给操作系统内部的协议栈来执行。这是因为和浏览器一样,解析器本身也不具备使用网络收发数据的功能。

解析器调用协议栈后,控制流程会再次转移,协议栈会执行发送消息的操作,然后通过网卡将消息发送给DNS服务器(上图④⑤)。

HTTP消息是用文本编辑的,但DNS消息是使用二进制数据编写的。

向DNS服务器发送消息时,我们当然也需要知道DNS服务器的IP地址。只不过这个IP地址是作为TCP/IP的一个设置项目事先设置好的,不需要再去查询了。不同的操作系统中TCP/IP的设置方法也有差异,Windows中的设置如下图所示,解析器会根据这里设置的DNS服务器IP地址来发送消息。

在这里插入图片描述

1.3 全世界DNS服务器的大接力

1.3.1 DNS服务器的基本工作

DNS服务器的基本工作就是接收来自客户端的查询消息,然后根据消息的内容返回响应。

  • 域名

服务器、邮件服务器(邮件地址中@后面的部分)的名称

  • Class

在最早设计DNS方案时,DNS在互联网以外的其他网络中的应用也被考虑到了,而Class就是用来识别网络的信息。不过,如今除了互联网并没有其他的网络了,因此Class的值永远是代表互联网的IN

  • 记录类型

表示域名对应何种类型的记录。例如,当类型为A时,表示域名对应的是IP地址;当类型为MX时,表示域名对应的是邮件服务器。对于不同的记录类型,服务器向客户端返回的信息也会不同

DNS服务器上事先保存有以上这3种信息对应的记录数据,如下图所示。DNS服务器就是根据这些记录查找符合查询请求的内容并对客户端作出响应的。

在这里插入图片描述

虽然上图展示的是表格形式,但实际上这些信息是保存在配置文件中的,表格中的一行信息被称为一条资源记录。

1.3.2 域名的层次结构

DNS中的域名都是用句点来分隔的,比如www.lab.glasscom.com,这里的句点代表了不同层次之间的界限,就相当于公司里面的组织结构不用部、科之类的名称来划分,只是用句点来分隔而已。

在域名中,越靠右的位置表示其层级越高,比如www.lab.glasscom.com这个域名如果按照公司里的组织结构来说,大概就是“com事业集团glasscom部lab科的www”这样。其中,相当于一个层级的部分称为域。因此,com域的下一层是glasscom域,再下一层是lab域,再下面才是www这个名字。

1.3.3 寻找相应的DNS服务器并获取IP地址

请求DNS服务器时的关键在于如何找到我们要访问的Web服务器信息归哪一台DNS服务器管。

根域

com、jp这些域各自负责保存下级DNS服务器的信息,但它们并不是最顶层。在互联网中,com和jp的上面还有一级域,称为根域。根域不像com、jp那样有自己的名字,因此在一般书写域名时经常被省略,如果要明确表示根域,应该像www.lab.glasscom.com.这样在域名的最后再加上一个句点,而这个最后的句点就代表根域。不过,一般都不写最后那个句点,因此根域的存在往往被忽略,但根域毕竟是真实存在的,根域的DNS服务器中保管着com、jp等的DNS服务器的信息。由于上级DNS服务器保管着所有下级DNS服务器的信息,所以我们可以从根域开始一路往下顺藤摸瓜找到任意一个域的DNS服务器。
在这里插入图片描述

DNS服务器之间的查询操作

根域的DNS服务器信息被保存在互联网中所有的DNS服务器中,这样一来,任何DNS服务器就都可以找到并访问根域DNS服务器了。

分配给根域DNS服务器的IP地址在全世界仅有13个,而且这些地址几乎不发生变化,因此将这些地址保存在所有的DNS服务器中也并不是一件难事。

在这里插入图片描述

1.3.4 通过缓存加快DNS服务器的响应

在真实的互联网中,一台DNS服务器可以管理多个域的信息,即上级域和下级域有可能共享同一台DNS服务器。在这种情况下,访问上级DNS服务器时就可以向下跳过一级DNS服务器,直接返回再下一级DNS服务器的相关信息。

此外,有时候并不需要从最上级的根域开始查找,因为DNS服务器有一个缓存功能,可以记住之前查询过的域名。如果要查询的域名和相关信息已经在缓存中,那么就可以直接返回响应,接下来的查询可以从缓存的位置开始向下进行。并且,当要查询的域名不存在时,“不存在”这一响应结果也会被缓存。

这个缓存机制中有一点需要注意,那就是信息被缓存后,原本的注册信息可能会发生改变,这时缓存中的信息就有可能是不正确的。因此,DNS服务器中保存的信息都设置有一个有效期,当缓存中的信息超过有效期后,数据就会从缓存中删除。而且,在对查询进行响应时,DNS服务器也会告知客户端这一响应的结果是来自缓存中还是来自负责管理该域名的DNS服务器。

1.4 委托协议栈发送消息

1.4.1 数据收发操作概览

和向DNS服务器查询IP地址的操作一样,这里也需要使用Socket库中的程序组件。不过这个过程有点复杂,发送数据是一系列操作相结合来实现的。

向操作系统内部的协议栈发出委托时,需要按照指定的顺序来调用Socket库中的程序组件。

在这里插入图片描述

在进行收发数据之前,双方需要先建立起通信管道。建立管道的关键在于管道两端的数据出入口,这些出入口称为套接字。我们需要先创建套接字,然后再将套接字连接起来形成管道。

整个通信过程如下:

  1. 服务器一方先创建套接字。然后等待客户端向该套接字连接管道。
  2. 客户端创建一个套接字,从该套接字延伸出管道连接到服务器端,通信准备完成。
  3. 通信。
  4. 断开连接并删除套接字。

注:

管道连接是由客户端发起的,但是断开时可以由客户端或服务端做任意一方发起。一方断开后,另一方也会随之断开,管道断开后套接字也会被删除,通信结束。

1.4.2 创建套接字阶段

客户端创建套接字的操作和调用解析器一样,调用Socket库中的socket程序组件即可。调用socket使控制流程会转移到socket内部并执行创建套接字的操作,完成之后控制流程又会被移交回应用程序。

  • 描述符

套接字创建完成后,协议栈会返回一个描述符,应用程序会将收到的描述符存放在内存中。描述符是用来识别不同的套接字的,大家可以作如下理解。我们现在只关注了浏览器访问Web服务器的过程,但实际上计算机中会同时进行多个数据的通信操作,比如可以打开两个浏览器窗口,同时访问两台Web服务器。这时,有两个数据收发操作在同时进行,也就需要创建两个不同的套接字。这个例子说明,同一台计算机上可能同时存在多个套接字,在这样的情况下,我们就需要一种方法来识别出某个特定的套接字,这种方法就是描述符。我们可以将描述符理解成给某个套接字分配的编号。也许光说编号还不够形象,大家可以想象一下在酒店寄存行李时的场景,酒店服务人员会给你一个号码牌,向服务人员出示号码牌,就可以取回自己寄存的行李,描述符的原理和这个差不多。当创建套接字后,我们就可以使用这个套接字来执行收发数据的操作了。这时,只要我们出示描述符,协议栈就能够判断出我们希望用哪一个套接字来连接或者收发数据了。

应用程序是通过“描述符”这一类似号码牌的东西来识别套接字的。

在这里插入图片描述

1.4.3 连接阶段:把管道接上去

现在需要委托协议栈将客户端创建的套接字与服务器那边的套接字连接起来。应用程序通过调用Socket库中的名为connect的程序组件来完成这一操作。这里的要点是当调用connect时,需要指定描述符、服务器IP地址和端口号这3个参数(上图②)。

connect的3个参数:

  1. 描述符

描述符就是在创建套接字的时候由协议栈返回的那个描述符。connect会将应用程序指定的描述符告知协议栈,然后协议栈根据这个描述符来判断到底使用哪一个套接字去和服务器端的套接字进行连接,并执行连接的操作。

  1. IP地址

通过DNS服务器查询得到的我们要访问的服务器的IP地址。

  1. 端口号

只知道IP地址,我们就可以识别出网络上的某台计算机。但是,连接操作的对象是某个具体的套接字,因此必须要识别到具体的套接字才行,而仅凭IP地址是无法做到这一点的。当同时指定IP地址和端口号时,就可以明确识别出某台具体的计算机上的某个具体的套接字。

注:

服务器上所使用的端口号是根据应用的种类事先规定好的,比如Web是80号,电子邮件是25号。

客户端在创建套接字时,协议栈会为这个套接字随便分配一个端口号,当协议栈执行连接操作时,会将这个随便分配的端口号通知给服务器,服务器也就知道了客户端的端口号。

区分两个概念

描述符:应用程序用来识别套接字的机制。

IP地址和端口号:客户端和服务器之间用来识别对方套接字的机制。

1.4.4 通信阶段:传递消息

应用程序无法直接控制套接字,因此还是要通过Socket库委托协议栈来完成这个操作。

这个操作需要使用write这个程序组件,具体过程如下。

首先,应用程序需要在内存中准备好要发送的数据。
根据用户输入的网址生成的HTTP请求消息就是我们要发送的数据。

接下来,当调用write时,需要指定描述符和发送数据(上图③),然后协议栈就会将数据发送到服务器。
由于套接字中已经保存了已连接的通信对象的相关信息,所以只要通过描述符指定套接字,就可以识别出
通信对象,并向其发送数据。

接着,发送数据会通过网络到达我们要访问的服务器。

接下来,服务器执行接收操作,解析收到的数据内容并执行相应的操作,向客户端返回响应消息。

当消息返回后,需要执行的是接收消息的操作。接收消息的操作是通过Socket库中的read程序组件委托
协议栈来完成的(上图③')。调用read时需要指定用于存放接收到的响应消息的内存地址,这一内存地
址称为接收缓冲区。由于接收缓冲区是一块位于应用程序内部的内存空间,因此当消息被存放到接收缓冲
区中时,就相当于已经转交给了应用程序。

1.4.5 断开阶段:收发数据结束

当浏览器收到数据之后,收发数据的过程就结束了。接下来,我们需要调用Socket库的close程序组件进入断开阶段(上图④)。最终,连接在套接字之间的管道会被断开,套接字本身也会被删除。

Web使用的HTTP协议规定,当Web服务器发送完响应消息之后,应该主动执行断开操作,因此Web服务器会首先调用close来断开连接。断开操作传达到客户端之后,客户端的套接字也会进入断开阶段。接下来,当浏览器调用read执行接收数据操作时,read会告知浏览器收发数据操作已结束,连接已经断开。浏览器得知后,也会调用close进入断开阶段。

HTTP协议将HTML文档和图片都作为单独的对象来处理,每获取一次数据,就要执行一次连接、发送请求消息、接收响应消息、断开的过程。因此,如果一个网页中包含很多张图片,就必须重复进行很多次连接、收发数据、断开的操作。对于同一台服务器来说,重复连接和断开显然是效率很低的,因此后来人们又设计出了能够在一次连接中收发多个请求和响应的方法。在HTTP版本1.1中就可以使用这种方法,在这种情况下,当所有数据都请求完成后,浏览器会主动触发断开连接的操作。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

蓝带915

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值