用户向浏览器输入一条URL到响应返回,一条网络请求的生命周期。
全书共分六合部分:
- 应用层客户端生成HTTP,委托给操作系统的协议栈
- 协议栈(TCP/IP模块)调用网卡驱动生成电信号
- 网卡如何通过路由器到达用于接入互联网的路由器
- 互联网内部接力传输
- 到达web服务器之后先通过防火墙的检查
- web服务器是如何收取数据的
第一章主要介绍了,客户端应用从解析URL到委托协议栈发送的主流程:
- 应用层客户端根据url协议格式取出,域名或ip,port,URL, 请求参数等信息
- 按照HTTP协议生成请求消息
- 发送消息之前,需要知道对方的IP, 委托DNS客户端解析器使用域名通过DNS服务器获取IP
- 使用 Socket 库委托协议栈(TCP/IP)发送请求
主要看点如下:
生成 HTTP 消息
- 用户向浏览器输入了一个网址(URL),浏览器是如何解析这个网址(URL)的呢
- 浏览器根据URL生成一条HTTP消息,HTTP消息具体长啥样呢?
向 DNS 服务器获取 web server IP
- 在浏览器是如何通过域名来查找IP的
全球 DNS 服务器大接力
- 上万台的DNS是如何接力完成IP查询的
委托协议栈发送消息
- 协议栈是什么
- 具体是如何委托的
生成HTTP请求信息
浏览器输入网址(URL)
URL Uniform Resource Locator 统一资源定位器
URL 格式 -- 协议类型://协议格式
用HTTP协议访问Web服务器时
http://user:[email protected]:80/dir/file1.htm
http://[用户名]:[密码]@web服务器域名:[端口号]文件路径名
ftp上传下载文件
ftp://user:[email protected]:21/dir/file1.htm
ftp://[用户名]:[密码]@ftp服务器域名:[端口号]文件路径名
file://localhost/c:/path/file.zip
file://[计算机名]文件路径名
mailto:[email protected]
mailto:邮件地址
HTTP 的基本思路
client ---- 请求消息[URI|方法] ---> server
client <--- 响应消息[状态码] ---- server
请求消息包括对什么,进行怎样的操作。
对什么 称为 URI : Uniform Resource Identifier 统一资源标识符, 包括 URL
进行怎样的操作 称为 方法: GET POST ...
HTTP 协议格式
请求消息
<方法><空格><空格>
<字段名>:<字段值>
<字段名>:<字段值>
<字段名>:<字段值>
...
<空行>
<消息体>
响应消息
<空格><状态码><空格><响应短语>
<字段名>:<字段值>
<字段名>:<字段值>
<字段名>:<字段值>
...
<空行>
<消息体>
请求头分类: 通用头(适用于请求头 响应头) 请求头 响应头 实体头
响应码 | 响应短语
1xx | 告知请求处理进度和情况
2xx | 成功
3xx | 表示需要进一步操作
4xx | 客户端错误
5xx | 服务器错误
一条请求中只能写一个URI, html 和 图片都需要单独的请求
WWW 工作原理, 网页中的文本数据和嵌入其中的图片数据是独立存储|分开请求的
向 DNS 服务器查询 Web 服务器的 IP 地址
上一步生成了 HTTP 消息, 发送之前需要知道对方服务器的IP。
DNS: Domain Name System 源码服务器
IP 地址
IP 由网络号和主机号组成,网络号和主机号的分界线由子网掩码划分。
ip查看指令
windows ipconfig
linux ifconfig
举例说明:
ip: 10.11.12.13
子网掩码: 255.255.255.0
网络号:10.11.12
主机号:13
32 bit, 8 bit 一组
a. IP地址主体的表示方式
10.11.12.13
IP地址
b. 子网掩码表达方式
10.11.12.13/255.255.255.0
IP地址主体/子网掩码
c. 采用网络号比特数表示子网掩码
10.11.12.13/24
IP地址主体/子网掩码
d. 表示子网的地址
10.11.12.0/24
主机号所有比特位都为 0 代表整个子网
d. 表示子网的地址
10.11.12.255/24
主机号所有比特位都为 1 代表对子网进行广播
ip地址 10.11.12.255
子网掩码 255.255.255.0
子网掩码表示网络号与主机号的边界, 子网掩码1的部分表示网络号, 0的部分主机号
网络号比特数: 24 == 255.255.255.0
域名和 IP 地址并用
人用域名, 容易记
路由器用IP, 地址长度 32bit 4字节, 网络传输效率高, 性能好
note: 如果服务器使用虚拟主机, 可能无法用 IP 访问
如何查询 IP
1. 询问最近的 DNS服务器, 域名会对应 IP
2. DNS服务器返回 IP
计算机上会有一个 DNS客户端 称为 DNS解析器
通过 DNS 查询 IP 被称为域名解析
解析器实际是一段程序, 包含在操作系统的 Socket库中
Socket库 加州大学伯克利开发的BSD(UNIX操作系统)中的C语言库, 其他语言参照 Socket 开发了相应的网络库
Socket库 是用于调用网络功能的程序组件集合, 网络开发的标准库
BSD (Berkeley Software Distribution,伯克利软件套件)
https://baike.baidu.com/item/BSD/3794498?fr=aladdin
通过 DNS解析器 向 DNS服务器 发送查询
<内存地址> = gethostbyname("域名");
解析器工作流程
网络应用程序调用解析器时,程序的控制流程会转移到解析器的内部。
1. 应用程序调用 DNS解析器
2. DNS解析器 生成 DNS服务器查询消息,调用协议栈(TCP/IP驱动)
3. 协议栈发送消息
4. 通过网卡发送消息给 DNS 服务器。
HTTP 消息用文本, DNS 消息用二进制
控制流程转移:应用程序调用其他程序,原本运行的程序进入暂停状态,被调用的程序开始运行。
全世界 DNS服务器 大接力
DNS 服务器的工作流程
1. 接收来自客户端的查询消息
2. 根据消息内容返回响应
查询消息格式
a) 域名
服务器, 邮件服务器([email protected] @后面的这一段)名称
b) Class
类型永远是代表互联网的 IN
c) 记录类型
A: 服务器
MX(mail eXchange): 邮件服务器
响应消息格式
记录类型为A 返回 服务器对应的IP
记录类型为MX 返回 邮件服务器对应的优先级和域名
优先级:一个邮件地址对应多个邮件服务器时,数字越小优先级越高
域名 | Class | 记录类型 | 响应数据 | |
---|---|---|---|---|
www.baidu.com | IN | A | xxx.xxx.xxx.xxx | |
glasscom.com | IN | MX | 10 mail.glasscom.com | |
mail.glasscom.com | IN | A | xxx.xxx.xxx.xxx |
域名层次结构
按域名分层次结构的保存
www.baidu.com 句点分隔, 越靠右层级越高
可直接百度"域名层次结构"
寻找相应的 DNS服务器并获取 IP 地址
1. 从下向上注册
2. 从上向下查询
注册
DNS服务器A(管理baidu.com)
DNS服务器B(管理com)
A注册baidu.com以及A的ip到B
B注册com以及B的ip到根服务器(.)
根域服务器的IP存放于所有DNS服务器中
根域服务器的IP全世界仅13个, 使用多台服务器对应一个IP
查询
客户端先访问距离最近的DNS服务器K, K的ip在客户端的TCP/IP配置中有
例如 www.baidu.com
K 访问根域, 返回com域所在的ip
K 访问com域, 返回baidu域所在的ip
K 访问baidu域, 返回www域所在的ip
K 访问www域, 返回www.lab.glasscom.com所在的ip
最后K返回ip给客户端
DNS服务器缓存加速
查询域名后 DNS服务器会进行缓存
域名不存在也会被缓存
DNS 服务器中的缓存信息会设置一个有效期。并会告知客户端,响应结果来自缓存还是管理该域名的服务器
缓存:将使用过的数据存放在离使用该数据较近的高速存储装置中,以便提高后续访问速度的技术。
CPU和内存之间 磁盘和内存之间 网络缓存
委托协议栈发送消息
数据收发操作
按顺序调用 Socket 库中的程序组件,向OS内部的协议栈发出委托。
1. 创建套接字(创建套接字阶段)
2. 将管道连接到服务器套接字(连接阶段)
3. 手法数据(通信阶段)
4. 断开连接并删除套接字(断开阶段) 可以有客户端服务器任一方发起,通常服务器
<内存地址> = gethostbyname("www.baidu.com");
<描述符> = socket(, <流模式>);
connect(<描述符>, <服务器的IP地址和端口号>, ...);
write(<描述符>, <发送数据>, <发送数据长度>);
<接收数据长度> = read(<描述符>, <接收缓冲区>, ...);
close(<描述符>);
这5个操作都是应用程序委托OS的协议栈来执行的。
这些委托操作都是通过调用Socket库中的程序组件执行的,Socket库起到应用程序和协议栈桥梁作用
socket(, <流模式>); 附上一篇参数详解(https://blog.csdn.net/lee244868149/article/details/43732025)
TCP是一种流模式的协议
UDP是一种数据报模式的协议
本文中 Socket/socket/套接字
Socket,表示库
socket,表示程序组件名称
套接字,表示管道两端的接口,网络中不同主机上的应用进程之间进行双向通信的端点的抽象。套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议栈进行交互的接口。
创建套接字
<描述符> = socket(, <流模式|bio|nio>)
应用程序、操作系统通过套描述符来识别套接字
通过描述符,协议栈可以找到对应的套接字
连接阶段
connect(<描述符>, <服务器的IP地址>, <服务器端口号>, ...);
描述符:协议栈根据描述符判断使用哪个套接字和服务端的套接字进行连接,并执行连接
服务器IP:识别服务器
服务器端口:识别服务器上的套接字
创建套接字时,协议栈会分配一个端口号(也可以指定)。连接操作时将这个端口号通知给服务器
调用 connect 时,执行连接操作。连接成功后,协议将将对方 IP PORT 等信息保存在套接字中
描述符、端口号与套接字的关联关系
描述符:应用程序用于识别套接字的机制
IP+PORT:客户端和服务端之间识别对方套接字的机制
IP地址时分配给设备中安装的网络硬件的。如果一台设备有多个网络硬件则有多个IP
默认端口号
http 80
tomcat 8080
电子邮件 25
通信阶段:传递消息
write(<描述符>, <发送数据>, <发送数据长度>);
<接收数据长度> = read(<描述符>, <接收缓冲区>, ...);
通过 socket 调用 read write 委托协议栈发送接收信息
接收缓冲区位于应用程序内部,消息存放到接收缓冲区相当于转交给了应用程序
断开阶段:收发数据结束
应用程序收到数据,收发数据的过程就结束了。接下来调用 Socket 的 close 进入断开阶段。
最终套接字和管道断开,套接字本身会被删除。
根据应用种类不同,客户端和服务器哪边先close。有些应用客户端先执行,有些服务端先执行。
断开流程
HTTP协议规定:服务器先断开
web服务器发送完响应消息后,主动执行断开操作,首先调用close断开连接
web客户端收到断开的信号,进入断开阶段
接下来,浏览器(应用程序)调用read接收数据,read告知浏览器(应用程序)收发数据操作已结束,连接已断开
浏览器(应用程序)得知后,调用close进入断开阶段
HTTP 1.1 开始连接复用
实际负责收发消息的是协议栈、网卡、驱动