读书笔记-《网络是怎样连接的》笔记2 第一章

1.1 生成 HTTP 请求消息

用户在浏览器中输入网址后,浏览器对网址进行解析,根据网址的含义来生成请求消息。浏览器通过请求消息将用户需要哪些数据告知服务器。

  • 浏览器如何解析网址
  • 请求消息实际的样子

1.1.1 探索之旅从输入网址开始

URL: Uniform Resource Locator,统一资源定位符。用来判断浏览器该使用其中哪种功能来访问相应的数据。
URL 开头的文字,即“http:”“ftp:”“file:”“mailto:”这部分文字都表示浏览器应当使用的访问方法。

浏览器是一个具备多种客户端功能的综合性客户端软件,因此它需要 一些东西来判断应该使用其中哪种功能来访问相应的数据,而各种不同的 URL 就是用来干这个的。
当访问 Web 服务器时应该使用 HTTP协议;访问 FTP 服务器(上下载和上传文件)时则应该使用 FTP 协议。因此我们可以把这部分理解为访问时使用的协议类型
开头部分的内容决定了后面部分的写法。

URL的各种格式

1.1.2 浏览器先要解析 URL

浏览器第一步工作就是对 URL 进行解析,从而生成发送给服务器的请求消息。

当对URL进行解析时,首先需要按照URL的格式将其中的各个元素拆分出来,然后,通过拆分出来的这些元素就能够明白URL代表的含义。

下面以访问Web服务器的情况为例:
Web浏览器解析URL的过程
图 1.2(b)中的 URL 表示要访问 www.lab.glasscom.com 这个 Web 服务器上路径名为/dir/file1.html 的文件,也就是位于 /dir/ 目录下的 file1.html 这个文件。

1.1.3 省略文件名的情况

我们会在服务器上事先设置好文件名省略时要访问的默认文件名。这个设置根据服务器不同而不同,大多数情况下是 index.html 或者 default.htm 之类的文件名。因此,省略文件名时,服务器就会访问这个默认文件。
(a)http://www.lab.glasscom.com/dir/
(b)http://www.lab.glasscom.com/
(c)http://www.lab.glasscom.com
(d)http://www.lab.glasscom.com/whatisthis

(a):会访问/dir/index.html 或者 /dir/default.htm
(b)(c):会访问 /index.html 或者/default.htm
(d):如果 Web 服务器上存在名为 whatisthis 的文件,则将 whatisthis 作为文件名来处理;如果存在名为 whatisthis 的目录,则将 whatisthis 作为目录名来处理

1.1.4 HTTP 的基本思路

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

  • 首先,客户端会向服务器发送请求消息。请求消息中包含的内容是“对什么”(URI)和“进行怎样的操作”(方法)两个部分。

    URI:Uniform Resource Identifier,统一资源标识符
    URI的内容是一个存放网页数据的文件名或者是一个CGI 程序的文件名,例如 “/dir1/file1.html” /dir1/program1.cgi”等,也可以直接使用“http:”开头的 URL。可以写各种访问目标,而这些访问目标统称为URI。
    CGI 程序:对 Web 服务器程序调用其他程序的规则所做的定义就是 CGI, 而按照 CGI 规范来工作的程序就称为 CGI 程序。
    方法:HTTP的主要方法

  • HTTP 消息中还有一些用来表示附加信息的头字段(可有可无)。客户端向 Web 服务器发送数据时,会先发送头字段,然后再发送数据。
  • 收到请求消息之后,Web 服务器会对其中的内容进行解析,并根据这些要求来完成工作,然后将结果存放在响应消息中。
  • 在响应消息的开头有一个状态码,它用来表示操作的执行结果是成功还是发生了错误。状态码后面就是头字段和网页数据。响应消息会被发送回客户端,客户端收到之后,浏览器会从消息中读出所需的数据并显示在屏幕上。

以GET方法为例:
首先,在请求消息中写上 GET 方法, 然后在 URI 中写上存放网页数据的文件名“/dir1/file1.html”,这就表示需要获取 /dir1/file1.html 文件中的数据。当 Web 服务器收到消息后,会打开 /dir1/file1.html 文件并读取出里面的数据,然后将读出的数据存放到响应消息中,并返回给客户端。最后,客户端浏览器会收到这些数据并显示在屏幕上。

1.1.5 生成 HTTP 请求消息

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

HTTP 消息在格式上是有严格规定的,因此浏览器会按照规定的格式来生成请求消息.
HTTP消息的格式
例:
在这里插入图片描述

1.1.6 发送请求后会收到响应

当我们将上述请求消息发送出去之后,Web 服务器会返回响应消息。

响应消息的格式以及基本思路和请求消息是相同的,差别只在第一行上。在响应消息中,第一行的内容为状态码响应短语,用来表示请求的执行结果是成功还是出错。

状态码和响应短语表示的内容一致,但它们的用途不同。

  • 状态码是一个数字,它主要用来向程序告知执行的结果
  • 响应短语则是一段文字,用来向人们告知执行的结果。

状态码:
状态码的第一位数字表示状态类型,第二、三位数字表示具体情况。

状态码含义
1xx告知请求的处理进度和情况
2xx成功
3xx表示需要进一步操作
4xx客户端错误
5xx服务器错误

返回响应消息之后,浏览器会将数据提取出来并显示在屏幕上,我们就能够看到网页的样子了。

由于每条请求消息中只能写 1 个 URI,所以每次只能获取 1 个文件, 如果需要获取多个文件,必须对每个文件单独发送 1 条请求。比如 1 个网页中包含 3 张图片,那么获取网页加上获取图片,一共需要向 Web 服务器发送 4 条请求。

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

请求消息生成之后,浏览器会委托操作系统向 Web 服务器发送请求,但浏览器必须告诉操作系统接收方的 IP 地址,因此浏览器需要向 DNS 服务器查询Web服务器对应的 IP 地址。

  • 如何向 DNS 服务器查询域名对应的 IP 地址

1.2.1 IP 地址的基本知识

TCP/IP的结构如下图所示:由一些小的子网(这里的子网可以理解为用集线器连接起来的几台计算机)通过路由器连接起来组成的一个大的网络。
IP的基本思路
通过 IP 地址我们可以判断出访问对象服务器的位置,从而将消息发送到服务器。

消息传送的过程:发送者发出的消息首先经过子网中的集线器,转发到距离发送者最近路由器上。接下来,路由器会根据消息的目的地判断下一个路由器的位置,然后将消息发送到下一个路由器,即消息再次经过子网内的集线器被转发到下一个路由器。前面的过程不断重复,最终消息就被传送到了目的地。

实际IP地址是一串32比特的数字,常见的IP地址格式是:按照8比特为一组分成4组,分别用十进制表示,然后用圆点隔开。但无法区分网络号和主机号。在IP地址的规则中,在组建网络时,用户可以自行决定它们之间的分配关系,因此我们还需要子网掩码来表示IP地址的内部结构。

子网掩码的格式是一串与 IP 地址长度相同的 32 比特数字,其左边一半都是 1,右边一半都是0。其中,子网掩码为 1 的部分表示网络号,子网掩码为 0 的部分表示主机号。
主机号部分全部为 0 代表整个子网而不是子网中的某台设备;
主机号部分全部为 1 代表向子网上所有设备发送包,即广播。
在这里插入图片描述

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

用域名更方便人们记忆,用IP地址相对于域名能减轻路由器的负担,减少传送数据时间;为了能够在人和机器双方都不做出牺牲的前提下完美地解决问题,采用DNS机制:通过名称来查询 IP 地址,或者通过 IP 地址来查询名称。

1.2.3 Socket 库提供查询 IP 地址的功能

Socket 库是用于调用网络功能的程序组件集合。解析器(我们的计算机上相当于 DNS 客户端的部分,用于域名解析)就是这个库中的其中一种程序组件。

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

Socket 库中的程序都是标准组件,只要从应用程序中进行调用就可以了。
解析器的调用方法
调用解析器后,解析器会向 DNS 服务器发送查询消息(这个操作委托给操作系统内的协议栈执行),然后 DNS 服务器会返回响应消息(包含查询到的 IP 地址),解析器会取出 IP 地址,并将其写入浏览器指定的内存地址中。浏览器在向 Web 服务器发送消息时,只要从该内存地址取出 IP 地址,并将它与 HTTP 请求消息一起交给操作系统就可以了。

1.2.5 解析器的内部原理

调用解析器时计算机内部的工作流程

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

全世界共有上万台 DNS 服务器,它们相互接力才能完成 IP 地址的查询。

  • 进行接力的方法

1.3.1 DNS服务器的基本工作

DNS 服务器的基本工作就是根据需要查询的域名和记录类 型查找相关的记录,并向客户端返回响应消息。
其中,来自客户端的查询消息包含以下 3 种信息。

  • 域名:服务器、邮件服务器(邮件地址中@后面的部分)的名称
  • Class:用来识别网络的信息。不过,如今只有互联网这个网络,因此 Class 的值永远是代表互联网的IN
  • 记录类型:表示域名对应何种类型的记录,对于不同记录类型,服务器向客户端返回的信息不同。例如,类型为A时表示域名对应IP地址MX表示域名对应邮件服务器

对于一个邮件地址,当需要知道这个地址对应的邮件服务器时,我们需要提供@后面的那一串名称。当记录类型为MX时,DNS 服务器会在记录中保存两种信息,分别是邮件服务器的优先级和域名。(优先级数值较小的邮件服务器代表更优先。)
DNS服务器的基本工作

1.3.2 域名的层次结构

DNS 服务器中的所有信息都是按照域名以分层次的结构来保存的。

DNS 中的域名都是用句点来分隔的,比如www.lab.glasscom.com,这里的句点代表了不同层次之间的界限。

在域名中,越靠右的位置表示其层级越高,其中,相当于一个层级的部分称为域。比如www.lab.glasscom.com 这个域名,com 域的下一层是 glasscom 域,再下一层是 lab 域,再下面才是www这个名字。

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

首先,将负责管理下级域的 DNS 服务器的 IP 地址注册到它们的上级 DNS 服务器中,然后上级 DNS 服务器的 IP 地址再注册到更上一级的 DNS 服务器中,以此类推。

这样,我们就可以通过上级 DNS 服务器查询出下级 DNS 服务器的 IP 地址,也就可以向下级DNS服务器发送查询请求了。

在互联网中,com 和 jp 的上面还有一级域,称为根域,在一般书写域名时经常被省略。由于上级 DNS 服务器保管着所有下级 DNS 服务器的信息,所以我们可以从根域开始一路往下顺藤摸瓜找到任意一个域的 DNS 服务器。

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

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

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

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

注意:信息被缓存后,原本的注册信息可能会发生改变,这时缓存中的信息就有可能是不正确的。因此DNS服务器中保存的信息都设置有一个有效期,超过有效期后,数据就会从缓存中删除。

在对查询进行响应时,DNS服务器也会告知客户端这一响应的结果是来自缓存中还是来自负责管理该域名的DNS服务器。

1.4 委托协议栈发送消息

查询到 IP 地址之后,浏览器就可以将消息委托给操作系统发送给 Web服务器了。

  • 委托是如何完成的

1.4.1 数据收发操作概览

收发数据的操作分为4个阶段:
(1)创建套接字(创建套接字阶段)
(2)将管道连接到服务器端的套接字上(连接阶段)
(3)收发数据(通信阶段)
(4)断开管道并删除套接字(断开阶段)

在每个阶段,Socket 库中的程序组件都会被调用来执行相关的数据收发操作(都是由操作系统中的协议栈来执行的)。

首先,服务器一方先创建套接字,然后等待客户端向该套接字连接管道。客户端也会先创建一个套接字,然后从该套接字延伸出管道,最后管道连接到服务器端的套接字上。当双方的套接字连接起来之后,通信准备就完成了。
当数据全部发送完毕之后,连接的管道将会被断开。
管道在连接时是由客户端发起的,但在断开时可以由客户端或服务器任意一方发起。其中一方断开后,另一方也会随之断开,当管道断开后,套接字也会被删除。通信操作结束。

客户端和服务器之间收发数据操作的情形

1.4.2 创建套接字阶段(图1.18 ①)

客户端创建套接字的操作非常简单,只要调用 Socket 库中的 socket 程序组件就可以了。调用 socket 之后,控制流程会转移到 socket 内部并执行创建套接字的操作,完成之后控制流程又会被移交回应用程序。

套接字创建完成后,协议栈会返回一个描述符,应用程序会将收到的描述符存放在内存中。描述符是用来识别不同的套接字的。

当创建套接字后,我们就可以使用这个套接字来执行收发数据的操作了。这时,只要我们出示描述符, 协议栈就能够判断出我们希望用哪一个套接字来连接或者收发数据。

1.4.3 连接阶段:把管道接上去(图1.18 ②)

我们需要委托协议栈将客户端创建的套接字与服务器那边的套接字连接起来。

应用程序通过调用 Socket 库中的名为 connect 的程序组件来完成这一操作。当调用 connect 时,需要指定描述符、 服务器 IP 地址和端口号这 3 个参数。

描述符:应用程序用来识别套接字的机制
IP地址端口号:客户端和服务器之间用来识别对方套接字的机制

如果说描述符是用来在一台计算机内部识别套接字的机制,那么端口号就是用来让通信的另一方能够识别出套接字的机制。

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

端口号详细讲解见 6.1.3节
客户端在创建套接字时,协议栈会为这个套接字随便分配一个端口号,当协议栈执行连接操作时,会将这个随便分配的端口号通知给服务器。

1.4.4 通信阶段:传递消息(图1.18 ③)

只要将数据送入套接字,数据就会被发送到对方的套接字中。这个操作需要使用Socket 库中的write 这个程序组件。

首先,应用程序需要在内存中准备好要发送的数据(用户输入的网址生成的HTTP请求)。
接下来,当调用 write 时,需要指定描述符和发送数据,然后协议栈就会将数据发送到服务器。(只要通过描述符指定套接字,就可以识别出通信对象,并向其发送数据。)
发送数据会通过网络到达我们要访问的服务器。
接下来,服务器执行接收操作,解析收到的数据内容并执行相应的操作,向客户端返回响应消息。
当消息返回后,需要执行的是接收消息的操作。

接收消息的操作是通过 Socket 库中的 read 程序组件委托协议栈来完成的。

调用 read 时需要指定用于存放接收到的响应消息的内存地址,这一内存地址称 为接收缓冲区
由于接收缓冲区是一块位于应用程序内部的内存空间,因此当消息被存放到接收缓冲区中时,就相当于已经转交给了应用程序。

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

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

断开的过程如下:

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

HTTP 协议将HTML文档和图片都作为单独的对象来处理,每获取一次数据,就要执行一次连接、发送请求消息、 接收响应消息、断开的过程。因此,如果一个网页中包含很多张图片,就必须重复进行很多次这样的操作。

对于同一台服务器来说,重复连接和断开显然是效率很低的,因此后来人们又设计出了能够在一次连接中收发多个请求和响应的方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值