计算机网络

键入网址到网页显示,期间发生了什么?

一.浏览器的第一步工作是解析URL

首先浏览器做的第一步工作就是要对URL进行解析,从而生成发送给Web服务器的请求信息。

所以图中的长长的 URL 实际上是请求服务器里的文件资源。

要是上图中的蓝色部分 URL 元素都省略了,那应该是请求哪个文件呢?

当没有路径名是,就代表访问目录下事先设置的默认文件,也就是/index.html或者/default.html这些文件,这样就不会发送混乱了。

二.生产HTTP请求信息

对URL进行解析之后,浏览器确定了Web服务器和文件名,接下来就是根据这些信息生成HTTP请求消息了。

一个孤单 HTTP 数据包表示:“我这么一个小小的数据包,没亲没友,直接发到浩瀚的网络,谁会知道我呢?谁能载我一程呢?谁能保护我呢?我的目的地在哪呢?”。充满各种疑问的它,没有停滞不前,依然踏上了征途!

三.真实地址查询——–DNS

通过浏览器解析URL并生成HTTP消息后,需要委托操作系统将消息发送给Web服务器。

但在发送之前还有一项工作需要完成,那就是查询服务器域名对应的IP地址,因为委托操作系统发送消息时,必须提供通信对象的IP地址。

所以有一种服务器专门保存了Web服务器域名与IP的对应关系,他就是DNS服务器

域名的层级关系

DNS中的域名都是用句号来分隔的,比如www.server.com ,这里的句点代表了不同层次之间的界限。

在域名中,越靠右的位置表示其层级越高

实际上域名最后还有一个点,比如www.server.com. 这最后个点代表根域名

也就是,. 根域是在最顶层,它的下一层就是 .com 顶级域,再下面是 server.com

所以域名的层级关系类似一个树状结构:

  • 根 DNS 服务器(.)
  • 顶级域 DNS 服务器(.com)
  • 权威 DNS 服务器(server.com)

根域的 DNS 服务器信息保存在互联网中所有的 DNS 服务器中。

这样一来,任何 DNS 服务器就都可以找到并访问根域 DNS 服务器了。

因此,客户端只要能够找到任意一台 DNS 服务器,就可以通过它找到根域 DNS 服务器,然后再一路顺藤摸瓜找到位于下层的某台目标 DNS 服务器。

域名解析的工作流程

  1. 客户端首先会发出一个 DNS 请求,问 www.server.com 的 IP 是啥,并发给本地 DNS 服务器(也就是客户端的 TCP/IP 设置中填写的 DNS 服务器地址)。
  2. 本地域名服务器收到客户端的请求后,如果缓存里的表格能找到 www.server.com,则它直接返回 IP 地址。如果没有,本地 DNS 会去问它的根域名服务器:“老大, 能告诉我 www.server.com 的 IP 地址吗?” 根域名服务器是最高层次的,它不直接用于域名解析,但能指明一条道路。
  3. 根 DNS 收到来自本地 DNS 的请求后,发现后置是 .com,说:“www.server.com 这个域名归 .com 区域管理”,我给你 .com 顶级域名服务器地址给你,你去问问它吧。”
  4. 本地 DNS 收到顶级域名服务器的地址后,发起请求问“老二, 你能告诉我 www.server.com 的 IP 地址吗?”
  5. 顶级域名服务器说:“我给你负责 www.server.com 区域的权威 DNS 服务器的地址,你去问它应该能问到”。
  6. 本地 DNS 于是转向问权威 DNS 服务器:“老三,www.server.com对应的IP是啥呀?” server.com 的权威 DNS 服务器,它是域名解析结果的原出处。为啥叫权威呢?就是我的域名我做主。
  7. 权威 DNS 服务器查询后将对应的 IP 地址 X.X.X.X 告诉本地 DNS。
  8. 本地 DNS 再将 IP 地址返回客户端,客户端和目标建立连接。

至此,我们完成了 DNS 的解析过程。现在总结一下,整个过程我画成了一个图。

那是不是每次解析域名都要经过那么多的步骤呢?

当然不是了,还有缓存这个东西的嘛。

浏览器会先看自身有没有对这个域名的缓存,如果有,就直接返回,如果没有,就去问操作系统,操作系统也会去看自己的缓存,如果有,就直接返回,如果没有,再去 hosts 文件看,也没有,才会去问「本地 DNS 服务器」。

数据包表示:“DNS 老大哥厉害呀,找到了目的地了!我还是很迷茫呀,我要发出去,接下来我需要谁的帮助呢?”

指南好帮手——协议栈

通过DNS获取到IP后,就可以把HTTP请求的传输工作交给操作系统中的协议栈

协议栈的内部分为几个部分,分别承担不同的工作。上下关系是有一定的规则,上面的部分会向下的部分委托工作,下面的部分收到委托的工作并执行。

应用程序(浏览器)通过调用Socket库,来委托协议栈工作。协议栈的上半部分有两块,分别是TCPUDP协议,这两个传输协议会接受应用层的委托执行收发数据的操作。

协议栈的下面一半是用IP协议控制网络包收发操作,在互联网上传数据时,数据会被切分成一块块的网络包, 而将网络包发送给对方的操作就是由IP负责的。

此外IP中还包括ICMP协议ARP协议

  • ICMP用于告知网络包传送过程中产生的错误以及各种控制信息。
  • ARP用于根据IP地址查询相应的以太网MAC地址

IP下面的网卡驱动程序负责控制网卡硬件,而最下面的物理硬件网卡则负责完成实际的收发操作,也就是对网线中的信号执行发送和接收操作。

数据包看了这份指南表示:“原来我需要那么多大佬的协助啊,那我先去找TCP大佬!”

可靠传输——-TCP

HTTP是基于TCP协议传输的,所以在这我们先了解TCP协议。

TCP包头格式

先看看TCP报文头部格式

源端口号目的端口号是必不可少的,如果没有这两个端口号,数据就不知道应该发给哪个应用。

接下来的序号,这个是为了解决乱码问题。

还有应该有的是确认序列,目的是确认发送出去对方是否有收到。如果没有收到就应该重新发送,直到送到,确认序列是为了解决丢包问题

接下来还有一些状态位(第四行蓝色部分)。例如SYN是发起一个连接,ACK是回复,RST是重新连接,FIN是结束连接等。TCP是面向连接的,因而双方要维护连接的状态,这些状态位的包的发送,会引起双方的状态变化。

还有一个重要的是窗口大小。TCP要做流量控制,通信双方各声明一个窗口(缓存大小),标识自己当前能够的处理能力,别发送太快也别发送太慢。

除了做流量控制以外,TCP还会做拥塞控制,对于真正的通路堵车不堵车,它无能为力,唯一能做的就是控制自己,也即控制发送的速度。不能改变世界,就改变自己嘛。

TCP传输数据之前,要先三次握手建立连接

在 HTTP 传输数据之前,首先需要 TCP 建立连接,TCP 连接的建立,通常称为三次握手

这个所谓的「连接」,只是双方计算机里维护一个状态机,在连接建立的过程中,双方的状态变化时序图就像这样。

  • 一开始,客户端和服务端都处于closed状态。先是服务端主动监听某个端口,处于listen状态。’
  • 然后客户端主动发起连接SYN,之后处于SYN-SENT状态。
  • 服务端收到发起的连接,返回SYN,并且ACK客户端的SYN,之后处于SYN-REVD状态,
  • 客户端收到服务端发送的SYNACK之后,发送对SYN确认的ACK,之后客户端处于ESTABLISHED状态,因为它一发一收成功了。
  • 服务端收到自己ACKACK之后,处于ESTABLISHED状态,因为它也一发一收成功了。

所以三次握手目的是保证双方都有发送和接收的能力

如何查看TCP的连接状态?

TCP的连接状态可以在Linux通过netstat -napt命令查看

TCP分割数据

如果HTTP请求消息比较长,超过了MSS的长度,这时TCP就需要把HTTP的数据拆解成一块块的数据发送,而不是一次性发送所有数据。

  • MTU:一个网络包的最大长度,以太网中一般位1500字节。
  • MSS:除去IP和TCP头部之后,一个网络包所能容纳的TCP数据的最大长度。

数据会被以MSS的长度为单位进行拆分,拆分出来的每一块数据都会被放进单独的网络包中。也就是在每个被拆分的数据上加上TCP头信息,然后交给IP模块来发送数据。

TCP报文生成

TCP协议里面会有两个端口,一个是浏览器监听的端口(通常是随机生成),一个是Web服务器监听的端口(HTTP默认端口号是80,HTTPS默认端口号是443).

双方建立连接之后,TCP报文中的数据部分就是存放HTTP头部+数据,组装好TCP报文之后,就需要交给下面的网络层处理。

至此,网络包的报文如下图。

此时,遇上了 TCP 的 数据包激动表示:“太好了,碰到了可靠传输的 TCP 传输,它给我加上 TCP 头部,我不再孤单了,安全感十足啊!有大佬可以保护我的可靠送达!但我应该往哪走呢?”

远程定位—-IP

TCP模块在执行连接,收发,断开等各阶段操作时,都需要委托IP模块将数据封装成网络包发送给通信对象

IP包格式

在IP协议里面需要有源地址IP目的地址IP

  • 源地址IP,即是客户端输出的IP地址;
  • 目标地址,即通过DNS域名解析得到的Web服务器IP。

因为HTTP是经过TCP传输的,所以在IP包头的协议号要填写为06(十六进制),表示为TCP协议。

假设客户端有多个网卡,就会有多个IP地址,那IP头部的源地址应该选择哪个呢?

当存在多个网卡,在填写源地址IP时,就需要判断应该填写哪个地址。这个判断相当于在多块网卡中判断应该使用哪一个网卡来发送包。

这个时候就需要根据路由表规则,来判断哪一个网卡作为源地址IP。

在Linux操作系统中,我们可以使用route -n查看当前系统的路由表。

举个例子,根据上面的路由表,我们假设 Web 服务器的目标地址是 192.168.10.200

  1. 首先先和第一条目的子网掩码(Genmask)进行 与运算,得到结果为 192.168.10.0,但是第一个条目的 Destination192.168.3.0,两者不一致所以匹配失败。
  2. 再与第二条目的子网掩码进行 与运算,得到的结果为 192.168.10.0,与第二条目的 Destination 192.168.10.0 匹配成功,所以将使用 eth1 网卡的 IP 地址作为 IP 包头的源地址。

那么假设 Web 服务器的目标地址是 10.100.20.100,那么依然依照上面的路由表规则判断,判断后的结果是和第三条目匹配。

第三条目比较特殊,它目标地址和子网掩码都是 0.0.0.0,这表示默认网关,如果其他所有条目都无法匹配,就会自动匹配这一行。并且后续就把包发给路由器,Gateway 即是路由器的 IP 地址。

IP报文生成

至此,网络包的报文如下图。

此时,加上了 IP 头部的数据包表示 :“有 IP 大佬给我指路了,感谢 IP 层给我加上了 IP 包头,让我有了远程定位的能力!不会害怕在浩瀚的互联网迷茫了!可是目的地好远啊,我下一站应该去哪呢?”

两点传输——-MAC

生成了IP头部之后,接下来网络包还需要在IP头部的前面加上MAC头部

MAC包头信息

MAC头部是以太网使用的头部,它包含了接收方和发送方的MAC地址等信息。

在 MAC 包头里需要发送方 MAC 地址接收方目标 MAC 地址,用于两点之间的传输

一般在 TCP/IP 通信里,MAC 包头的协议类型只使用:

  • 0800 : IP 协议
  • 0806 : ARP 协议

ARP:地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议

MAC 发送方和接收方如何确认?

发送方的 MAC 地址获取就比较简单了,MAC 地址是在网卡生产时写入到 ROM 里的,只要将这个值读取出来写入到 MAC 头部就可以了。

接收方的 MAC 地址就有点复杂了,只要告诉以太网对方的 MAC 的地址,以太网就会帮我们把包发送过去,那么很显然这里应该填写对方的 MAC 地址。

TCP超时重传

image-20230619161935569

image-20230619161956519


计算机网络
http://example.com/2023/03/28/计算机网络/
Author
Posted on
March 28, 2023
Licensed under