第一章 WEB浏览器
1. 生成HTTP请求消息
1.1 输入网址
网址 = URL,可以“http:” “ftp:” “file:”开头
浏览器功能:访问WEB服务器、在FTP服务器上下载和上传文件、电子邮箱客户端
通过不同的URL来区分访问的功能
1.2 浏览器解析URL
1.3 省略文件名的情况
以“/”结尾:会访问服务器预先设置好的文件名(多数情况下是index.html/default.html)
例子:http://www.baidu.com/
省略结尾的“/”:没有路径名时,访问根目录下的默认文件
例子:http://www.baidu.com
省略文件名后缀:1.如果有此文件,则作为文件名处理 2.如果没有则作为路径处理
例子:http://www.baidu.com/doit
1.4 HTTP的基本思路
第一步:客户端向服务器端发送请求消息:包含URI和方法(需要让WEB服务器完成啥工作)
第二步:WEB服务器对内容进行解析,完成自己的工作,将结果存放在响应消息中
1.5 生成HTTP请求消息
消息第一行为请求行,重点是开头的方法,末尾加上HTTP版本号
如何判断应该使用的方法:根据浏览器的工作场景来决定
举例:在地址栏输入网址使用“GET”方法;如果是表单,可能用“GET”或“POST”
第二行开始为消息头,主要包含的头字段见下表
1.6 收到响应
响应消息与请求消息在第一行上有差异,响应消息的第一行为状态码和响应短语
当网页中包含图片,网页中的相关位置会嵌入表示图片文件的标签控制信息
2. 向DNS服务器查询WEB服务器的IP地址
IP地址的基本知识
浏览器本身不具备发送消息到网络的功能,需要委托操作系统来实现。
在发送消息前需要查询网址服务器域名对应的IP地址
TCP/IP的结构:
实际IP地址的格式:
通过子网掩码来区分网络号和主机号
1的部分表示网络号,0的部分表示主机号
主机号全0:表示整个子网
主机号全1:表示对子网上的所有设备发送包,即“广播”
2.2 域名和IP地址并用的理由
为何不用IP地址代替服务器名称? 因为服务器名称方便记忆
为何不用名称替代IP地址? 因为服务器名称的长度太长,会增加路由器负荷
2.3 Socket库提供查询IP地址的功能
DNS客户端的部分被称为DNS解析器,通过DNS查询IP地址的操作称为域名解析
Socket库包含的程序组件可以让其他应用程序调用操作系统的网络功能,DNS解析器是这个库中的一种程序组件
2.4 通过解析器向DNS服务器发出查询
编写浏览器等应用程序时,写上解析器的程序名称“gethostbyname”以及web服务器的域名,就可以完成对解析器的调用
调用解析器后,解析器会向DNS服务器发送查询消息,DNS服务器返回响应消息,在响应消息中查询IP地址并取出,然后存储到浏览器指定内存中。
2.5 解析器的内部原理
当应用程序调用解析器时,控制流程转移到解析器,解析器生成发送给DNS服务器的查询消息。(此过程和发送给WEB服务器的HTTP请求消息类似),解析器通过调用操作系统的协议栈来发送消息,最后通过网卡将消息发送到DNS服务器
向DNS服务器发送消息时,我们可以通过TCP/IP的设置项目知道DNS服务器的IP地址,不需要额外查询。不同操作系统的TCP/IP设置方法有差异。
3. DNS服务器大接力
3.1 DNS服务器的基本工作
DNS服务器的基本工作就是接收来自客户端的查询消息,包含以下三种信息:
(a) 域名
(b) Class 值永远代表互联网的IN
(c) 记录类型:表示域名对应何种类型的记录 A时代表域名对应IP地址 MX代表对应邮件服务
DNS服务器保存前面3种信息对应的记录数据,根据这些数据查找符合查询请求的内容
3.2 域名的层次结构
一台DNS服务器无法储存所有的服务器信息,需要将信息分布保存在多台DNS服务器中,通过相互配合,从而查找需要查询的信息
DNS服务器的信息都是按照域名以层次结构来保存的,域名中越靠右的位置代表层级越高,相当于一个层级的部分称作域
一个域的信息是作为整体存放在DNS服务器中的 -> DNS服务器也像域一样有层级关系
3.3 寻找相应的DNS服务器并获取IP地址
将负责管理下级域的DNS服务器IP地址注册到它的上级DNS服务器中
根域真实存在,在“com”,”cn”等顶层域之上,一般被忽略。从根域开始可以找到任意一个域的DNS服务器
另外还需要将根域的DNS服务器信息保存在互联网所有DNS服务器中
具体访问过程如下图:
3.4 通过缓存加快DNS服务器的响应
在真实的互联网中,一个DNS服务器可以管理多个域的信息
DNS服务器有缓存功能,可以记录之前查询过的域名,并且当要查询的域名不存在时,不存在这一结果也会被缓存
信息被缓存后,原先的注册信息可能发生改变,因此缓存中的信息有有效期
4. 委托协议栈发送消息
4.1 数据收发过程概览
向操作系统内部的协议栈发出委托时,需要按照指定顺序来调用Socket库中的程序组件
大致操作过程如图所示:
收发操作大致可以分为4个阶段:
(1)创建套接字
(2)将管道连接至服务器的套接字上,即连接阶段
(3)收发数据
(4)断开管道并删除套接字
需要注意的是浏览器不会去连接管道、放入数据,都是委托协议栈进行这些操作
4.2 创建套接字阶段
调用Socker库的socket组件来创建套接字,调用socket组件之后控制流程会转移到socket并执行创建套接字的操作,执行完后将控制流程移交回应用程序
套接字创建完成后,协议栈会返回一个描述符,应用程序会将此描述符放入内存中。一台计算机可以同时存在多个套接字,可以通过识别套接字的描述符来区别套接字。
4.3连接阶段
调用Socket库中的connect程序组件来进行连接操作,需要指定描述符、服务器IP地址和端口号
端口号需要解释一下:由于连接操作对象的是某个具体的套接字,因此必须识别计算机上的套接字才可以,只用IP无法做到这一点,所以需要端口号。
服务器上的端口号是根据应用实现确定好的:WEB是80端口 电子邮件是25端口
关于服务器如何识别用户端的端口号:客户端在创建套接字时会随机为套接字分配一个端口号,当协议栈执行连接操作时会将端口号告知给服务器
4.4 通信阶段
使用Socket 库的write程序组件实现传递消息
首先应用程序在内存中准备号需要发送的数据(http请求消息),当调用write时,需要指定操作符和发送数据,之后协议栈会将数据发送到服务器
之后服务器执行接收操作,并向客户端返回响应消息
消息返回后,使用Socket库中的read程序组件委托协议栈接收消息,将接收到的消息放入接收缓存区中。
4.5 断开阶段
调用Socket库中的close程序组件来进入断开阶段,最终套接字的管道断开,套接字删除
当WEB服务器发送完响应消息后,会主动执行断开操作,断开操作到达客户端后,客户端的套接字进入断开阶段。当浏览器调用read执行接收数据操作时,read会告知浏览器收发数据操作已结束,浏览器调用close进入断开阶段