第一章 浏览器生成消息
1、生成http请求消息
步骤: 输入网址(URL)–浏览器解析网址 – 生成http请求消息–发送请求消息后收到Web服务器返回的响应消息
浏览器的第一步工作是对 URL 进行解析。
(1)URL 统一资源定位符
- Web服务器: http:…
- FTP服务器: ftp:…
http 协议用于访问 Web 服务器,举一个 URL 的例子: http://(user:password@)www.glasscom.com:80/dir/file1.html
http:
表示URL访问的数据机制,也就是协议//
后面的字符串www.glasscom.com
表示 Web 服务器名/dir/file.html
:表示文件路径
浏览器要解析URL,得出Web服务器域名,数据源(文件)的路径名
**http协议中浏览器浏览网页其实就是访问Web服务器中的某个文件。
特殊URL情况
(2)http协议
定义了客户端和服务器间交互的消息内容和步骤: “对什么”(URI)+ “进行什么样的操作”(方法GET、POST…)
URI 通常是存放网页数据的文件名(“/dir/file.html”)或者CGI程序(“/dir/program1.cgi”)
-
Web服务器收到请求消息后会对内容进行解析,完成工作,将结果存放在响应消息之中。
-
响应消息开头有个状态码,表示执行结果成功还是错误,如“404 Not Found” ,状态码后面跟头字段和网页数据。
-
响应消息发送回客户端,客户端收到后,浏览器从响应消息中读出所需数据并显示在屏幕上。至此,完成整个http工作。
(3)浏览器生成http请求消息
- 解析 URL,确定 Web 服务器和文件名
- 生成 http 请求消息,有规定的格式
- Web 服务器返回响应消息
浏览器只能 解析URL 生成 http 消息,不具备将消息发送到网络的功能,发送消息的功能需要委托操作系统来实现(面向对象?)。
2、向 DNS 查询服务器地址
接上文,操作系统接受委托将消息发送到网络前,需要网址中服务器域名对应的 IP 地址。
(1)IP地址
实际上是一串 32 bit 的数字,按照 8 bit 为一组分为四组,再转化为 10 进制,包含着网络号与主机号,需要用到子网掩码作为附加信息表示 IP 地址的内部结构。
子网掩码用来确定网络号,子网掩码与ip地址做与操作后,得到的就是网络号,同一网络号下的地址可以相互通信,否则需要通过网关。
通过 DNS 可以查询IP地址,操作系统中负责解析域名的叫做解析器,是操作系统Socket库中的一段程序。
解析器:gethostbyname()
(2)解析器
调用: gethostbyname(www.glasscom.com)
<内存地址> = gethostbyname("www.lab.glasscom.com")
调用解析器后,解析器向DNS服务器发送查询消息,DNS 服务器随后返回包含IP地址的响应消息,解析器会取出IP地址并且写入浏览器指定的内存地址中。
3、DNS 服务器接力
DNS 基本工作: 接收来自客户端的查询消息,然后根据消息的内容返回响应。
查询消息内容:
- 域名
- Class:识别网络信息,现在只有互联网,用“IN”即可
- 记录类型:表示域名对应何种类型的记录。A-----IP地址;MX-----邮件服务器
DNS 服务器上事先保存了这三种信息对应的记录数据。DNS 服务器就是根据这些记录查找符合请求的内容并对客户端做出响应。
互联网中不计其数的服务器信息,如何能够查询?
(1)域名的层次结构
DNS 服务器中的信息按照域名以分层次的结构来保存。
www.lab.glasscom.com 这个域名为例,从上级域到下级域分别为
- com
- glasscom.com
- lab.glasscom.com
- www.lab.glasscom.com
(2)寻找对应DNS服务器
-
将负责管理下级域的DNS服务器的IP地址注册到他们的上级域DNS服务器中,以此类推。
-
根域中保存着 “cn”,“com”,"jp"等这些顶级域。
-
根域的DNS 服务器信息保存在互联网中所有的DNS服务器中。
做到上述三点,客户端只要能找到任意一台DNS 服务器,就能够顺藤摸瓜找到下属服务器。
- 客户端找到最近的 DNS 服务器A,发送查询消息。
- DNS 服务器A找到根域服务器,根据域名的层次结构层层下问。
- 找到存储该域名的IP地址的DNS服务器D,DNS服务器A得到该IP地址后,返回给客户端。
得到了IP地址后,就可以委托操作系统内部协议栈向目标IP地址发送消息。
4、委托协议栈发送消息
协议栈:操作系统内部的网络控制软件,也叫“协议驱动”,“TCP/IP驱动”等
向操作系统内部协议栈发出委托时,需要按照指定的顺序调用Socket库中的程序组件。
简单而言,收发数据的两台计算机会建立一条数据通道,数据双向流动。
- 创建套接字
- 将管道连接到服务器端的套接字上
- 收发数据
- 断开管道并删除套接字
浏览器委托收发数据的过程需要调用Socket库中的程序组件。
(1)创建套接字阶段
调用 socket 程序组件即可在客户端创建套接字,协议栈会返回一个描述符,用于识别套接字。
<描述符> = socket(<使用IPv4>,<流模式>,...);
(2)连接阶段
浏览器调用 Socket库中的 connect 程序组件完成,需要指定描述符、服务器IP地址和端口号。
connect(<描述符>,<服务器IP地址和端口号>,...);
同时指定IP地址和端口号时,可以明确识别出某台具体的计算机上的某个具体的套接字。服务器上的端口都是事先规定好的,Web服务器80号端口,电子邮件是25号端口。
(3)通信阶段
浏览器在内存中准备好要发送的数据,即根据用户输入的网址生产的http请求消息。
write(<描述符>,<发送数据>,<发送数据长度>)
服务器接收操作,解析收到的数据内容执行相应操作,向客户端返回相应消息。
消息返回后,需要调用 read 执行接收消息的操作。
read将接收到的响应消息存放到接收缓冲区,转接给了应用程序。
(4)断开阶段
调用Socket库中的close 程序组件进入断开阶段
HTTP 协议规定,Web 服务器发送完响应消息后,应主动执行断开操作。
- Web 服务器调用 close 断开连接
- 断开操作传达到客户端
- 客户端的套接字进入断开阶段
- 浏览器调用read时,read会告知浏览器收发数据操作已结束,调用close进入断开阶段。