第1章——浏览器生成消息
关键点:
- 生成HTTP请求消息
- 向DNS服务器查询Web服务器的IP地址
- 全世界DNS服务器的大接力
- 委托协议栈发送消息
1.1 生成HTTP请求消息
1.1.1 从输入网址开始
网址:URL(Uniform Resource Locator,统一资源定位符)。其前缀包括"http:"、“ftp:”、“file:”、"mailto:"等。
- 浏览器是一个具备多种客户端功能的综合性客户端软件(通过不同URL来使用相应功能):可以在FTP(File Transfer Protocal,文件传送协议)服务器下载和上传文件,同时也具备电子邮件客户端的功能。
图1.1列举了现在互联网中常见的URL,根据访问目标不同,URL的写法也不同。
- 例如访问Web服务器和FTP服务器时,URL中包含服务器的域名和访问文件的路径名等;
- 发邮件的URL则包含收件人的邮箱地址;
- 此外,根据具体情况,URL中还会包含用户名、密码、服务器端口号等。
1.1.2 浏览器要先解析URL
1.1.3 省略文件名的情况
-
http://www.lab.glasscom.com/dir/xx.xx
以"/"结尾代表/dir/后面本来应有的文件名xx.xx被省略。
当没有文件名时,会访问默认的文件名,例如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(Uniform Resource Identifier,统一资源标识符)。一般来说URI为文件名。
其中操作部分被称为方法,例如读取URI表示的数据、将客户端输入的数据发送给URI表示的程序等。 - 收到请求后,Web服务器会对其进行解析。根据URI和方法来完成工作,然后将结果存放在响应消息中。
响应消息开头有一个状态码,表示操作成功或失败,例如404 Not Found。
常用HTTP方法
- GET方法:访问Web服务器获取网页数据。首先在请求消息中写GET方法,然后在URI中写存放网页数据的文件名"/dir1/file1.html",表示我们需要获取/dir1/file1.html文件中的数据。
- POST方法:在表单(网页中的文本框、复选框等能够输入数据的部分)中填写数据并将其发送给Web服务器。在请求消息中,除了方法和URI,还要加上传递给程序和脚本的数据。
这两种方法属于HTTP的典型用法,而其他方法在互联网上几乎见不到使用的例子。
1.1.5 生成HTTP请求消息
解析URL后,浏览器确定了Web域名和文件名,然后根据这些信息生成HTTP请求消息。
- 当使用POST方法时,需要将表单中填写的信息写在消息体中。
- 当使用GET方法时,消息体中不需要填写数据。
1.1.6 发送请求后会收到响应
当Web服务器收到请求消息后,会返回响应信息。
如图1.5所示,响应消息的格式和请求消息相同,差别在于第一行。
- 状态码和响应短语表示的内容一致,但用途不同。
- 状态码给程序告知执行结果;
- 响应短语给人类告知执行结果。
HTTP状态码概要
状态码 | 含义 |
---|---|
1xx | 告知请求的处理进度和情况 |
2xx | 成功 |
3xx | 表示需要进一步操作 |
4xx | 客户端错误 |
5xx | 服务器错误 |
- HTML语言中,表示图片文件的标签为
<img src="image.jpg">
1.2 向DNS服务器查询Web服务器的IP地址
1.2.1 IP地址的基本知识
生成HTTP消息后,我们需要委托操作系统将消息发送给Web服务器。在此之前,我们需要查询网址域名对应的IP地址。
TCP/IP
- 互联网和局域网都是基于TCP/IP思路来设计的,其结构如图1.8所示。
- 简单说,就是由一些小的子网,通过路由器连接组成大的网络。
- 子网:用集线器连接起来的若干台计算机
- IP地址 = 网络号(分配给子网) + 主机号(分配给子网中的计算机)
- 通过IP地址我们可以判断访问对象服务器的位置,从而将消息发送到服务器。
IP地址
IP地址是一串32bite的数字,按照8bite(1字节)为1组分成4组,分别用十进制表示并用圆点隔开。
- 仅凭这串数字我们无法区分哪个是网络号,哪个是主机号。我们需要子网掩码来提供额外信息。
- 如图1.10所示,子网掩码为1的部分表示网络号,为0的部分表示主机号。
- 这种写法太长,也可以如图1.9(c)一样把1的部分的比特数用十进制表示写在IP地址右侧。
- 主机号全0:表示整个子网
- 主机号全1:表示向子网所有设备发送包,即“广播”
1.2.2 域名和IP地址并用的理由
- 人用域名(几十个字节)
- 路由器用IP地址(4个字节)
路由器不能用域名是因为,处理域名几十个到255个子节的字符会增加路由器负担,传送数据也会花费更长的时间。
DNS(Domain Name System,域名服务系统):将域名和IP地址进行关联是DNS最常见的用法。此外还可以关联邮件地址与邮件服务器。
1.2.3 Socket库提供查询IP地址的功能
对于DNS服务器,我们的计算机上有相应的DNS客户端,而相当于DNS客户端的部分成为DNS解析器。
- 域名解析:通过DNS查询IP地址的操作
- 解析器:负责域名解析的程序,包含在操作系统的Socket库中。
- Socket库:允许其他程序调用操作系统的网络功能。
1.2.4 通过解析器向DNS服务器发出查询
如图1.11展示了对解析器的调用。
1.2.5 解析器的内部原理
图1.12为调用解析器时计算机内部的工作流程
-
协议栈:操作系统内部的网络控制软件,也叫协议驱动、TCP/IP驱动。
-
tip:向DNS服务器发送消息时,我们也需要知道DNS服务器的IP地址。只不过这个IP地址已经作为TCP/IP的设置项目事先设置好了,不用再查询。
1.3 全世界DNS服务器的大接力
1.3.1 DNS服务器的基本工作
DNS服务器的基本工作:接收来自客户端的查询消息,并据此返回消息。
客户端的查询消息包括3种信息:
- 域名:服务器、邮件服务器的名称
- Class:在最早设计DNS方案时,DNS在互联网以外的其他网络中的应用也被考虑到了,而Class就是用来识别网络的。不过如今只存在互联网,所以Class的值永远是IN(代表互联网)
- 记录类型:表示域名对应何种类型的记录。例如为A时,表示域名对应的是IP地址;为MX时,表示域名对应的是邮件服务器。对应不同的记录类型,DNS服务器返回的消息也不同。
- 当记录类型为MX时,DNS服务器会在记录中保存两种信息:邮件服务器的域名和优先级(优先级数值较小的邮件服务器代表更优先)。
- 此外如图1.14,MX记录的返回消息还包括邮件服务器mail.glasscom.com的IP地址。
DSN服务器会从域名和IP地址的对照表中查找相应的记录,并返回IP地址。
1.3.2 域名的层次结构
在公司内部网络这样Web和邮件服务器数量有限的环境中,所有信息都可以保存在一台DNS服务器中,其工作方式和1.3.1节的内容完全符合。
然而在互联网中存在着无数的服务器,唯一的选择就是将信息分布保存在多台DNS服务器中,这些DNS服务器相互接力配合,从而查找出需要的信息。
- DNS服务器中的信息都是按照域名以分层次的结构来保存的。
- 域名中的"."代表不同层次的界限,越靠右的位置表示层级越高。每个层级称为域。
- 例如www.lab.glasscom.com。com域的下一层是glasscom域,再下一层是lab域,再下面才是www。
- 而NDS服务器也具有像域名一样的层次结构,每个域的信息都存放在对应层级的DNS服务器中。
1.3.3 寻找相应的DNS服务器并获取IP地址
- 将负责管理下级域的DNS服务器的IP地址注册到上级的DNS服务器中。
- 然后将上级DNS服务器的IP地址注册到更上一级的DNS服务器中。
- 根域:一般完整的域名应该类似于"www.lab.glasscom.com.",而最后的句点"."就代表根域,但一般会省略。
- 根域的DNS服务器中保存com、jp等顶级域的DNS服务器的信息。此外,将根域的DNS服务器信息保存在互联网所有的DNS服务器中,以便任意DNS服务器都能找到并访问根域DNS服务器。如图1.15所示。
- 全球的根域DNS服务器总共仅13个。
找到目标DNS服务器的过程
1.3.4 通过缓存加快DNS服务器的响应
在真实的互联网中,一台DNS服务器可以管理多个域的信息,而且上级域和下级域可能共享一台DNS服务器。
有时候不需要从根域开始查找,因为DNS服务器有一个缓存功能,可以记住之前查过的域名。
- 如果要查询的域名已经存在缓存中,那么就可以直接返回响应,接下来的查询可以从缓存位置开始向下进行。
- 如果要查询的域名不存在,“不存在”这一响应结果也会被缓存。这样,以后查询这个不存在的域名时,可以快速响应。
- DNS服务器缓存有一个有效期,过期后缓存会被清除。
1.4 委托协议栈发送消息
1.4.1 数据收发操作概览
- 收据收发操作不仅限于浏览器,所有使用网络的程序都适用。
- 向操作系统内部的协议栈发出委托时,需要按照指定的顺序来调用Socket库中的程序组件。
使用Socket库来收发数据(TCP协议)的操作过程如图1.17所示。
- 还有一种UDP(User Datagram Protocol,用户数据报协议)也可以用来收发数据。
套接字:数据收发管道的出入口。
协议栈的收发数据操作顺序:
- 创建套接字阶段:创建套接字
- 连接阶段:将管道连接到服务器的套接字上
- 通信阶段:收发数据
- 断开阶段:断开管道并删除套接字
其中每个阶段,Socket库中的程序组件都会被调用,但这些组件都充当桥梁的作用,而不执行实质性的操作。
1.4.2 创建套接字阶段
- socket组件
使用Socket库中的socket组件(其内部操作在第二章讲解)来创建套接字。创建完成后,协议栈会返回一个描述符,应用程序将收到的描述符放在内存中。
- 描述符是用来识别不同套接字的。
1.4.3 连接阶段
- connect组件
调用connect组件时,需要指定描述符、服务器IP地址和端口号。此时协议栈就会执行连接操作,连接成功后,就可以收发数据了。
- 客户端在创建套接字时,协议栈会给该套接字随便分配一个端口号。
- 描述符是用来在一台计算机内部识别套接字的机制。
- 端口号是让通信的另一方能够识别套接字的机制。
- 服务器上的端口号(第六章讲解)是根据应用的类型事先规定的。Web是80号端口,Email是25号端口。
1.4.4 通信阶段
- write组件
- read组件
现在依然需要通过Socket库委托协议栈来完成收发数据操作。
发送:
- 应用程序要在内存中准备好要发送的数据(HTTP请求消息就是我们要发送的数据)。
- 调用write组件并指定描述符和发送数据。
- 协议栈将数据发送到服务器。
接收:
调用read需要指定存放接收响应消息的内存地址(称接收缓冲区)。缓冲区是位于应用程序内部的内存空间,因此当消息存在接收缓冲区时,相当于转交给了应用程序。
1.4.5 断开阶段
- close组件
HTTP协议规定,当Web服务器发送完响应消息后,应主动执行断开操作。
- Web服务器会首先调用close组件来断开连接。
- 断开操作传达到客户端后,客户端的套接字也开始断开连接。
- 当浏览器调用read接收数据时,read会告知浏览器收发数据操作结束,连接断开。
- 浏览器得知后,也会调用close断开连接。
- HTTP版本1.1中允许在一次连接中收发多个请求和响应,所有数据都请求完成后,浏览器会主动触发断开连接的操作。