网络一 .浏览器生成消息
1.1 生成HTTP 请求
1.1.1 网络地址
URL : Uniform Resource Locator,统一资源定位符
可以是http : 也可以是ftp: 或者是 file:,URL 中会包含服务器的域名和要访问的文件的路径名等
http://user:password@www.glasscom.com:80/dir/file1.htm
ftp://user:password@ftp.glasscom.com:21/dir/file1.htm
file://localhost/c:/path/file1.zip
1.1.2 浏览器解析URL
http://www.lab.glasscom.com/dir1/file1.html
浏览器解析url,会根据协议的不同解析的规则也会有差异
1.1.3省略文件的情况
http://www.lab.glasscom.com/
##会默认登录 /default.html 或者/index.html 具体看服务器的设置
1.1.4 HTTP的基本思路
URI + 方法
方法的种类
方法 | 含义 |
---|
GET | 获取 URI 指定的信息。如果 URI 指定的是文件,则返回文件的内容;如果 URI 指定的是 CGI 程序,则返回该程序的输出数据 | POST | 从客户端向服务器发送数据。一般用于发送表单中填写的数据等情况下 | HEAD | 和 GET 基本相同。不过它只返回 HTTP 的消息头(message header),而并不返回数据的内容。用于获取文件最后更新时间等属性信息 | OPTIONS | 用于通知或查询通信选项 | PUT | 替换 URI 指定的服务器上的文件。如果 URI 指定的文件不存在,则创建该文件 | DELETE | 删除 URI 指定的服务器上的文件 | TRACE | 将服务器收到的请求行和头部(header)直接返回给客户端。用于在使用代理的环境中检查改写请求的情况 | CONNECT | 使用代理传输加密消息时使用的方法 |
服务端接受到URI和方法后 会响应数据到浏览器 浏览器解析数据并显示在浏览器上,到这里一个HTTP 请求完成了;
1.1.5 生成HTTP请求数据
回国头来,我们看看浏览器是如何的组件了一个HTTP 请求,HTTP 是一个协议 是客户端和服务端都相互遵守的协议规范,只有这样才可以基于协议解析数据和发送数据,协议规范了浏览器发送数据的格式
请求消息为
第一行称为请求行,通过这一行可以大致了解请求的内容:
<方法><空格><URI><空格><HTTP版本>
#第一行的末尾需要写上 HTTP 的版本号,这是为了表示该消息是基于哪个版本的 HTTP 规格编写的。到此为止,第一行就结束了
下一步法为消息头
<字段名>:<字段值>
......
......
......
<空格>
第二行开始为消息头。尽管通过第一行我们就可以大致理解请求的内容,但有些情况下还需要一些额外的详细信息,而消息头的功能就是用来存放这些信息。消息头的规格中定义了很多项目,如日期、客户端支持的数据类型、语言、压缩格式、客户端和服务器的软件名称和版本、数据有效期和最后更新时间等。这些项目表示的都是非常细节的信息,因此要想准确理解这些信息的意思,就需要对 HTTP 协议有非常深入的了解。表 1.2中列举了主要的头字段供大家参考,但不必全部弄明白。消息头中的内容随着浏览器类型、版本号、设置等的不同而不同,大多数情况下消息头的长度为几行到十几行
消息体
发送的数据 比如POST 的网页表单数据 ;在使用GET 方法的情况下,仅凭方法和 URI,Web 服务器就能够判断需要进行怎样的操作,因此消息体中不需要填写任何数据。
响应消息为
状态行
<HTTP版本><空格><状态码><空格><响应短语>
消息头
<字段名>:<字段值>
......
......
......
<空格>
消息体
消息体包含服务器向客户端发送的数据,例如从文件中读取的数据,或者CGI应用程序输出的数据等。消息体的内容作为二进制数据来处理;
尽管通过第一行我们就可以大致理解请求的内容,但有些情况下还需要一些额外的详细信息,而消息头的功能就是用来存放这些信息。消息头的规格中定义了很多项目,如日期、客户端支持的数据类型、语言、压缩格式、客户端和服务器的软件名称和版本、数据有效期和最后更新时间等;
消息头中的内容随着浏览器类型、版本号、设置等的不同而不同,大多数情况下消息头的长度为几行到十几行不等;
通用头:适用于请求和响应消息的头字段
头字段类型 | 含义 |
---|
Date | 表示请求和响应生成的日期 | Pragma | 表示数据是否允许缓存的通信选项 | Cache-Control | 控制缓存的相关信息 | Connection | 设置发送响应之后 TCP 连接是否继续保持的通信选项 | Transfer-Encoding | 表示消息主体的编码格式 | Via | 记录途中经过的代理和网关 |
请求头:用于表示请求消息的附加信息的头字段
头字段类型 | 含义 |
---|
Authorization | 身份认证数据 | From | 请求发送者的邮件地址 | If-Modified-Since | 如果希望仅当数据在某个日期之后有更新时才执行请求,可以在这个字段指定希望的日期。 一般来说,这个功能的用途在于判断客户端缓存的数据是否已经过期,如果已经过期则获取新的数据 | Referer | 当通过点击超级链接进入下一个页面时,在这里会记录下上一个页面的 URI | User-Agent | 客户端软件的名称和版本号等相关信息 | Accept | 客 户 端 可 支 持 的 数 据 类 型(Content-Type), 以MIME 类型来表示 | Accept-Charset | 客户端可支持的字符集 | Accept-Encoding | 客户端可支持的编码格式(Content-Encoding),一般来说表示数据的压缩格式 | Accept-Language | 客户端可支持的语言,汉语为 zh,英语为 en | Host | 接收请求的服务器 IP 地址和端口号 | If-Match | 参见 Etag | If-None-Match | 参见 Etag | If-Unmodified-Since | 当指定日期之后数据未更新时执行请求 | Range | 当需要只获取部分数据而不是全部数据时,可通过这个字段指定要获取的数据范围 |
响应头:用于表示响应消息的附加信息的头字段
头字段类型 | 含义 |
---|
Location | 表示信息的准确位置。当请求的 URI 为相对路径时,这个字段用来返回绝对路径 | Server | 服务器程序的名称和版本号等相关信息 | WWW-Authenticate | 当请求的信息存在访问控制时,返回身份认证用的数据(Challenge ①) | Accept-Ranges | 当希望仅请求部分数据(使用 Range 来指定范围) |
实体头:用于表示实体(消息体)的附加信息的头字段
头字段类型 | 含义 |
---|
Allow | 表示指定的 URI 支持的方法 | Content-Encoding | 当消息体经过压缩等编码处理时,表示其编码格式 | Content-Length | 表示消息体的长度 | Content-Type | 表示消息体的数据类型,以 MIME 规格定义的数据类型来表示 | Expires | 表示消息体的有效期 | Last-Modified | 数据的最后更新日期 | Content-Language | 表示消息体的语言。汉语为 zh,英语为 en | Content-Location | 表示消息体在服务器上的位置(URI) | Content-Range | 当仅请求部分数据时,表示消息体包含的数据范围 | Etag | 在更新操作中,有时候需要基于上一次请求的响应数据来发送下一次请求。 在这种情况下,这个字段可以用来提供上次响应与下次请求之间的关联信息。 上次响应中,服务器会通过 Etag 向客户端发送一个唯一标识, 在下次请求中客户端可以通过 If-Match、If-None-Match、If-Range 字段将这个标识告知服务器, 这样服务器就知道该请求和上次的响应是相关的。这个字段的功能和 Cookie 是相同的, 但 Cookie 是网景(Netscape)公司自行开发的规格,而 Etag 是将其进行标准化后的规格 |
1.1.6 请求发送后收到响应
WEB 服务器接收到浏览器的数据后,服务器会响应消息,在响应的消息中,有服务端处理响应的结果,这个结果一般使用状态码来表示
HTTP 状态码概要
状态码 | 含义 |
---|
1xx | 告知请求的处理进度和情况 | 2xx | 成功 | 3xx | 表示需要进一步操作 | 4xx | 客户端错误 | 5xx | 服务器错误 |
一次请求 一个URI对应一个响应
1.2 客户端查询服务端IP 地址
1.2.1 IP 地址的基本知识
上面说的请求和响应是基于网络通讯,而浏览器本身是不具备有发送消息到网络的能力的,网络的功能是浏览器委托操作系统内核去做的事情;在委托操作系统发送请求的时候,得先知道服务端的对应IP 地址;
互联网和公司内部的局域网都是基于 TCP/IP 的思路来设计的,所以我们先来了解 TCP/IP 的基本思路。TCP/IP 的结构就是由一些小的子网,通过路由器连接起来组成一个大的网络。每个路由器下面又可能又许多子网;这样就组成了一个庞大的网络;
通过 IP 地址我们可以判断出访问对象服务器的位置,从而将消息发送到服务器;
实际的 IP 地址是一串32 比特的数字,按照 8 比特(1 字节)为一组分成 4 组,分别用十进制表示然后再用圆点隔开。这就是我们平常经常见到的 IP 地址格式,但仅凭这一串数字我们无法区分哪部分是网络号,哪部分是主机号。在 IP 地址的规则中,网络号和主机号连起来总共是 32 比特
##IP 地址主体
10.11.12.1~254 # 0,255 看下面
##IP+ 掩码{掩码和ip主体一直方式 可以不一致}
10.11.12.13/255.255.255.0
#表示整个子网 主机比特为0 0 代表整个子网而不是子网中的某台设备
10.11.12.0
#子网广播 主机比特都是1 全部为 1 代表向子网上所有设备发送包 即广播
10.11.12.255
IP地址 10. 1. 2.3 00001010.00000001.00000010.00000011
掩码 255.255.255.0 11111111.11111111.11111111.00000000
网络号 10. 1. 2. 00001010.00000001.00000010
主机号 3 00000011
注意:子网掩码表示网络号与主机号之间的边界。在本例中,这个边界与字节的边界是正好吻合的,也就是正好划分在句点的位置上,实际上也可以划分在字节的 中间位置。
1.2.2 为什么用域名
IP 地址相比较来说难记 只用域名的话字符对路由器运算比较消耗资源 所有有DNS 域名解析
1.2.3 Socket库
Socket库 (可以理解这个库是操作系统和网络先关的功能)
其中一个组件resolver [域名与IP的转换]
1.2.4 通过DNS查询IP
DNS:Domain Name System
浏览器输入域名之后,浏览器委托操作系统的Socket库 查询IP地址 后续讲解详细详细
然后浏览器在根据IP 地址去服务器请求,
1.2.5 解析器内部原理
1.浏览器输入地址
2.浏览器调用操作系统 resolver
3.操作系统发起一个UDP请求
4.委托网卡
5.到达DNS服务器
6.网卡接收DNS 服务器信息
7.UDP接收数据
8.resolver 接收到IP 信息
9.IP 信息放回给应用程序内存
10.浏览器发送请求
注意: DNS 服务器发送消息时,我们当然也需要知道 DNS 服务器的 IP 地址。只不过这个 IP 地址是作为 TCP/IP 的一个设置项目事先设置好的,不需要再去查询了
1.3 DNS接力
1.3.1 基础简介
DNS 服务器的基本工作就是接收来自客户端的查询消息,然后根据消息的内容返回响应。 客户端的查询包含以下 3 种信息。
1.域名
服务器、邮件服务器(邮件地址中 @ 后面的部分)的名称
2. Class
在最早设计 DNS 方案时,DNS 在互联网以外的其他网络中的应用也被考虑到了,而 Class 就是用来识别网络的信息。不过,如今除了互联网并没有其他的网络了,因此 Class 的值永远是代表互联网的 IN
3.记录类型
表示域名对应何种类型的记录。例如,当类型为 A 时,表示域名对应的是 IP 地址;当类型为 MX 时,表示域名对应的是邮件服务器。对于不同的记录类型,服务器向客户端返回的信息也会不同
DNS 相当于维护一张表
域名 | Class | 记录类型 | 响应数据(IP) |
---|
www.xxx.com | IN | A | 1.1.1.1 [对应ip] | xxx2.com | IN | MX | 10 mail.xxx1.com [优先级;邮件服务器域名] | mail.xxx1.com | IN | A | 2.2.2.2 [对应ip] | | IN | PTR | 域名相关别名的 CNAME | | IN | NS | 查询 DNS 服务器 IP 地址 | | IN | SOA | 查询域名属性信息 |
示例
##查询域名
(a)域名 = www.xxx.com
(b) Class = IN
(c)记录类型 = A
放回 1.1.1.1
##查询邮件服务器 tone@xxx1.com 发送邮件
(a)域名 = xxx1.com
(b) Class = IN
(c)记录类型 = MX
1.3.2 域名层次结构
所有域名在一台DNS服务器上是不可能的;信息分布保存在多台 DNS 服务器中,这些 DNS 服务器相互接力配合,从而查找出要查询的信息;。不过,这个机制其实有点复杂,因此我们先来看一看信息是如何在 DNS 服务器上注册并保存的。
用句点来分隔而已 A。在域名中,越靠右的位置表示其层级越高,比如 www.lab.glasscom.com 这个域名如果按照公司里的组织结构来说,大概就是“com 事业集团 glasscom 部 lab 科的 www”这样。其中,相当于一个层级的部分称为域。因此,com 域的下一层是glasscom 域,再下一层是 lab 域,再下面才是 www 这个名字。
一个域的信息是作为一个整体存放在 DNS 服务器中的,不能将一个域拆开来存放在多台 DNS 服务器中。不过,DNS 服务器和域之间的关系也并不总是一对一的,一台 DNS 服务器中也可以存放多个域的信息;
于是,DNS 服务器也具有了像域名一样的层次结构,每个域的信息都存放在相应层级的 DNS 服务器中;
比如 www.nikkeibp.co.jp 这个域名,最上层的 jp 代表分配给日本这个国家的域;下一层的 co 是日本国内进行分类的域,代表公司;再下层的 nikkeibp 就是分配给某个公司的域;最下层的 www 就是服务器的名称。
1.3.3寻找相应的 DNS 服务器并获取 IP 地址
注册机制:
首先,将负责管理下级域的 DNS 服务器的 IP 地址注册到它们的上级 DNS 服务器中,然后上级 DNS 服务器的 IP 地址再注册到更上一级的 DNS 服务器中
也就是说,负责管理 lab.glasscom.com 这个域的 DNS 服务器的 IP 地址需要注册到 glasscom.com 域的 DNS服务器中,而 glasscom.com 域的 DNS 服务器的 IP 地址又需要注册到 com域的 DNS 服务器中。
com、jp 这些域(称为顶级域);com 和 jp 的上面还有一级域,称为根域
根域的 DNS 服务器信息保存在互联网中所有的 DNS 服务器中。任何 DNS 服务器就都可以找到并访问根域 DNS 服务器了;分配给根域 DNS 服务器的 IP 地址在全世界仅有 13 个(但是服务器数据是很多的)
## 查询 www.lab.glasscom.com
1.PC先获取到最近的DNS服务器 DNS1
2.DNS1 中获取根DNS服务器 DNSroot
3.DNS1去 DNSroot 获取下级域名com 的DNS服务器 DNScom
4.DNS1去 DNScom 获取下级域名com 的DNS服务器 DNSglasscom.com
5.DNS1去 DNSglasscom.com 获取下级域名com 的DNS服务器 DNSlab.glasscom.com
6.DNS1去 DNSlab.glasscom.com 获取下级域名com 的DNS服务器 DNSwww.lab.glasscom.com ==>获取IP
7.DNS1把IP 信息缓存 并放回到PC
1.3.4 缓存加快响应
有时候并不需要从最上级的根域开始查找,因为 DNS 服务器有一个缓存功能,可以记住之前查询过的域名。如果要查询的域名和相关信息已经在缓存中,那么就可以直接返回响应,接下来的查询可以从缓存的位置开始向下进行。相比每次都从根域找起来说,缓存可以减少查询所需的时间;如果数据源于缓存也会告知客户端;
1.4 委托协议栈发送消息
1.4.1 数据收发操作概览
先来介绍一下收发数据操作的整体思路
服务器程序—>服务器协议栈(TCP) ----->服务器网卡 -----> 服务器 ----> 客户端----->客户端网卡 -----> 客户端协议栈(TCP) —> 客户端程序
(1)创建套接字(创建套接字阶段)
(2)将管道连接到服务器端的套接字上(连接阶段)
(3)收发数据(通信阶段)
(4)断开管道并删除套接字(断开阶段)
1.4.2 创建套接字阶段
客户端创建套接字的操作非常简单,只要调用 Socket 库中的 socket 程序组件,套接字创建完成后,协议栈会返回一个描述符,程序收到文件描述符负载内存中,一个连接一个套接字
1.4.3连接阶段:把管道接上去
调用 Socket 库中的名为 connect 的程序组件来完成这一操作;是当调用 connect 时,需要指定描述符、服务器 IP 地址和端口号这 3 个参数
参数
1.描述符 创建套接字的时候由协议栈返回值,描述符对应套接字去和服务端连接
2.服务器 IP 地址 DNS发挥的服务器IP 地址
3.端口号 端口号是服务端程序运行的端口
后续会详细讲解
1.4.4 通信阶段:传递消息
只要将数据送入套接字,数据就会被发送到对方的套接字中。当然,应用程序无法直接控制套接字,因此还是要通过 Socket 库委托协议栈来完成这个操作。这个操作需要使用 write 这个程序组件
程序需要准备好要发送的数据 -----write {描述符,发送数据 }---->服务器 继而响应数据 返回
read 接收缓冲区
1.4.5断开阶段:收发数据结束
要调用 Socket 库的 close 程序组件进入断开阶段;套接字本身也会被删除
|