探索之旅看点
1.当从浏览器中输入URL(Uniform Resource Locator)后,浏览器会从网址(URL)开始解析.
2.根据解析后的数据来生成请求消息.
3.浏览器"委托操作系统"向Web服务器发送请求并告诉系统接收方的IP地址(浏览器需要向DNS服务器查询域名对应的IP地址)
4.全世界的上万台DNS服务器接力完成IP地址的查询
5.查询IP地址后,向Web服务器发送消息
HTTP请求
简介
生成HTTP请求
可以将开头部分理解为访问时的"协议类型",尽管后面的写法不同,但开头决定了后面的写法,所以不会造成混乱的现象.
2.Web服务器收到消息后根据URI进行解析,并返回响应消息,在响应消息的开头有一个状态码,我们可以通过返回的状态码来判断本次消息的成功或失败,失败原因等.
3.当浏览器收到Web服务器响应消息后, 无论成功或失败, 都会将响应的数据显示到屏幕上.
4.HTTP整个工作完成
请求头
响应头
当消息发送到Web服务器后,就会收到对应的响应消息,与请求头唯一的区别就在第一行中,第一行的内容为状态吗和响应短语,表示请求的执行结果.状态码是一个数字,它用来向程序告知执行结果, 下表列出了基本常用的状态码概要:
状态码 | 含义 |
---|---|
1xx | 请求的处理进度与情况 |
2xx | 成功 |
3xx | 需要进一步操作 |
4xx | 客户端错误 |
5xx | 服务器错误 |
当网页信息为纯文字时,则直接显示到屏幕上,请求到此结束,如果还有图片资源需要显示,则在源码中插入标签,用来占用图片显示的位置并且向服务请求获取响应图片显示在预留空间中.
注:每一张图片都会向服务器请求一次,如3张图片,一个URI,则需要向服务器请求4次,请求与响应都是一对一的.(在HTTP1.1 中已经做了优化处理,当某个请求完成时,服务端不会进行close操作,当所有数据请求完成后,浏览器/客户端会主动发起close操作)
向DNS服务器查询域名对应的IP地址
这里还有一个效率问题,域名转换为IP地址提高了运行效率, 因为IP地址的长度为32比特(4字节),相对域名最短几十个字节,最长255字节而言,减少了路由器的负担,传送数据的时间也相对减少.
在转换域名与IP地址之间的机制就称为DNS.
那么,DNS是如何查询IP的呢?其实很简单,就是调用包含在"Socket库"中的解析器来实现的,当我们通过DNS来查询IP时,通过将Socket中的解析器调用结果,存储到浏览器的内存中,待浏览器向Web服务器发送消息时, 从内存中取出对应的IP地址和HTTP一起返回给操作系统进行解析.
一句话来概括就是: 域名查询IP地址时,浏览器会使用Socket库中的解析器
那么解析器内部是如何实现的?
解析器的内部实现原理
这里进行一个简单的介绍:
1.浏览器/应用程序 存储的IP内存空间 = 使用高级编程语言,调用Socket库根据域名来调用方法
2.Scoket库生成发送给DNS服务器的查询消息
3.委托给操作系统内部协议栈将消息发送出去(操作系统内部网络控制软件,也叫 TCP/IP驱动 等)
4.通过网卡发送给DNS服务器
5.查询到结果后通过网卡返回查询结果并保存到内存中
6.继续执行下一行代码,待调用时机,在对应内存中取出查询到的IP地址
tip: 只要是在DNS服务器中注册的,都可以作为Web服务器的域名来使用
一句话来概括就是: DNS服务器会从域名与IP地址的对照表中查找相应的记录并返回对应的IP地址
当查询请求提交到DNS服务器后,会先找到最近的DNS服务器进行查询,如果查询需要的IP地址存在根域中,那么,根据当前DNS服务器存储的根域信息向上查找IP地址,直到查到为止.
DNS服务器的优化处理:
1.通过上级DNS服务器查询出下级服务器的IP地址,也可以向上级发送查询请求
2.DNS服务器利用了分布式存储的方式
3.查询后的IP地址会进行缓存操作,并且会设置对应的缓存时间. 在查询响应时, DNS服务器会告知客户端是来自缓存或管理该域名的DNS服务器.
TCP/IP
套接字
什么是套接字?
Web浏览器/应用程序 在与DNS服务器进行交互的时候,需要创建一个连接管道,用于它们之间的交互,传输信息等操作,而这个连接管道,其实就是套接字.
在它的内部可以在连接时在TCP模块处创建表示连接控制信息的头部,同时,通过TCP头部中的发送方和接收方端口号可以找到要连接的套接字.这也就是区分了同步网络情况下对应的套接字连接.
三次握手
网络连接图解简单说一下连接建立的阶段 (后面两个阶段稍后做分析)
连接建立的阶段 : 当TCP头部创建好后委托IP模块将数据发送给服务器,服务器根据IP模块接收到数据后,根据传送过来的头信息找到对应的数据,使用套接字写入相关信息,并将状态改成正在连接.当完成套接字的连接后,服务器需要利用TCP模块返回响应,在服务器的TCP头部中设置发送方和接收方端口号以及SYN比特(如果某些原因无法接受连接,那么将不会设置SYN,而是将RST比特设置为1),此外,再返回响应时还需要将ACK控制位设置为1,表示已经收到响应网络包.
那么为什么要设置这几个字段?
在网络连接的过程中可能会发生错误,发生丢失.因此双方进行通信必须确认网络包是否送达,而设置ACK比特就是用来进行这一确认.
接下来网络包会传输到客户端,用过IP模块到达TCP模块,通过TCP头部信息确认是否操作成功,如果SYN为1则表示成功.这时会向套接字写入一些信息,并将状态改为连接完毕(将ACK比特设置为1并回调给服务器告知响应包已经收到).客户端完成操作.
tips:
当应用程序发送给协议栈的数据长度达不到MTU值时,需要等数据累积到一定量时再发送.当数据达不到要求并且间隔一定时间后,协议栈内存在一个计时器,会将网络包发出去.
(应用程序可以指定不等待填满缓冲出直接发送)
MTU: 一个网络报的最大长度, 以太网中一般为1500字节
MSS: 出去头部后, 一个网络所能容纳的TCP数据的最大长度.
一句话来概括就是:通过 "序号" 和 "ACK号" 可以确认接收方是否收到网络包
网络延迟时间处理
当网络包延迟的时候,TCP采用了动态调整等待时间的方法,这样做优化了
- 等待时间过长,导致访问速度缓慢
- 等待时间过短,可能发生重传了包之后,前面的ACK号才姗姗来迟 (如果最短时间无法正确测量,则有一个默认值,0.5 - 1之间)
滑动窗口
那么在等到返回时间的时候,如果不进行任何的操作,这块时间将被浪费,为了减少这样的浪费,TCP采用了"滑动窗口"的方式来节省浪费的时间.
不等待ACK号返回,直接发送一系列包.
滑动窗口 基本实现思路: 接收方会告知发送发自己的"包缓冲区" 最多可以接受多少比特的包数据,然后发送方根据这个峰值来进行包发送的控制操作.
滑动窗口原理