What Happens When You Type a Url in Your Browser and Press Enter
当您在浏览器中输入 URL 并按 Enter 键时会发生什么
Disclaimer: Hello! This is my first blog post! I’m super excited to share it with the world but should also warn you that it’s a bit long and repetitive. Hopefully, I’ll become a better writer as I blog more. I hope you enjoy it :)
免责声明:您好!这是我的第一篇博客文章!我非常高兴与全世界分享它,但也应该警告您,它有点长且重复。希望随着我写博客的增多,我会成为一名更好的作家。我希望你喜欢它 :)
Introduction 介绍
I’ve heard this question many times during my career and want to try to answer it. I’m going to dive deep into the networking part of the question since this is the part that I find the most interesting.
在我的职业生涯中,我多次听到这个问题,并想尝试回答它。我将深入探讨问题的网络部分,因为这是我觉得最有趣的部分。
A lot of stuff happens under the hood in the network to get an HTTP request from the browser to the server and then an HTTP response from the server back to the browser. To be able to explain what happens, I’m going to make some assumptions about the network setup and the status of the network.
网络中发生了很多事情,以获取从浏览器到服务器的 HTTP 请求,然后从服务器返回到浏览器的 HTTP 响应。为了能够解释发生的情况,我将对网络设置和网络状态做出一些假设。
Assumptions 假设
Network status 网络状态
- Our computer is connected to the network via Ethernet.
我们的计算机通过以太网连接到网络。 - Our computer already has an IP address (more on what the IP address is later).
我们的计算机已经有一个IP地址(稍后详细介绍IP地址是什么)。 - Our computer sits behind a NAT (this is the case in many home networks).
我们的计算机位于 NAT 后面(许多家庭网络都是这种情况)。 - Our ARP cache is clear.
我们的 ARP 缓存是清空的。 - Our DNS cache is clear.
我们的 DNS 缓存是清晰的。 - Our router’s ARP cache contains an entry for its default gateway.
我们的路由器的 ARP 缓存包含其默认网关的条目。 - Our network is
192.168.0.0/24
.
我们的网络是192.168.0.0/24
。 - The URL we’re going to use is
http://www.example.com
.
我们要使用的 URL 是http://www.example.com
。 - The DNS server’s cache has an entry for
www.example.com
.
DNS 服务器的缓存有一个www.example.com
条目。 - We’re going to ignore TCP sequence numbers.
我们将忽略 TCP 序列号。
Configuration 配置
Our computer (computer making the HTTP request)
我们的计算机(发出 HTTP 请求的计算机)
- IP Address:
192.168.0.10
. IP地址:192.168.0.10
。 - Default gateway:
192.168.0.1
. 默认网关:192.168.0.1
。 - DNS Server:
8.8.8.8
. DNS 服务器:8.8.8.8
。 - MAC Address:
AA:AA:AA:AA:AA:AA
. MAC地址:AA:AA:AA:AA:AA:AA
。 - TCP source port:
9999
.
TCP源端口:9999
。 - DNS source port:
3333
.
DNS源端口:3333
。
Our router / NAT
我们的路由器/NAT
- Internal IP Address:
192.168.0.1
.
内部IP地址:192.168.0.1
。 - External IP address:
51.0.0.20
.
外部IP地址:51.0.0.20
。 - External TCP source port:
15000
.
外部 TCP 源端口:15000
。 - External DNS source port:
10000
.
外部 DNS 源端口:10000
。 - External net mask:
255.255.255.0
(or/24
).
外部网络掩码:255.255.255.0
(或/24
)。 - Internal MAC address:
BB:BB:BB:BB:BB:BB
.
内部MAC地址:BB:BB:BB:BB:BB:BB
。 - External MAC address:
CC:CC:CC:CC:CC:CC
.
外部MAC地址:CC:CC:CC:CC:CC:CC
。 - Default gateway:
51.0.0.1
. 默认网关:51.0.0.1
。 - Default gateway’s MAC address:
DD:DD:DD:DD:DD:DD
.
默认网关的MAC地址:DD:DD:DD:DD:DD:DD
。
www.example.com server www.example.com 服务器
- The IP address of
www.example.com
is93.184.216.34
.
www.example.com
的IP地址是93.184.216.34
。
Step by step 一步步
To get this process started we type the URL http://www.example.com
in the web browser and press enter. This will instruct our browser to create an HTTP request to send to www.example.com
. The HTTP request will look something like this:
要开始此过程,我们在网络浏览器中输入 URL http://www.example.com
,然后按 Enter 键。这将指示我们的浏览器创建一个 HTTP 请求发送到 www.example.com
。 HTTP 请求将如下所示:
GET / HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
HTTP request to www.example.com
.
对 www.example.com
的 HTTP 请求。
Our computer will now try to connect to www.example.com
in TCP port 80
(the default HTTP port). First, it needs to create a TCP SYN
segment to initiate the TCP connection. The SYN
segment contains information to establish the connection including a random source port (9999
from our assumptions), destination port (80
) and a flag (SYN
).
我们的计算机现在将尝试连接到 TCP 端口 80
(默认 HTTP 端口)中的 www.example.com
。首先,它需要创建一个TCP SYN
段来发起TCP连接。 SYN
段包含建立连接的信息,包括随机源端口(我们假设为 9999
)、目标端口( 80
)和标志( SYN
)。
This TCP segment is then encapsulated in an IP packet that contains the source IP (192.168.0.10
) and the destination IP. For the destination IP, our computer goes to its DNS cache and looks for an entry containing www.example.com
. Since its cache is empty, the creation of the IP packet needs to wait until we can get the IP address of www.example.com
. So far our incomplete IP packet looks something like this:
然后,该 TCP 段被封装在包含源 IP ( 192.168.0.10
) 和目标 IP 的 IP 数据包中。对于目标 IP,我们的计算机会前往其 DNS 缓存并查找包含 www.example.com
的条目。由于它的缓存是空的,所以IP数据包的创建需要等到我们可以获得 www.example.com
的IP地址。到目前为止,我们不完整的 IP 数据包看起来像这样:
IP[
SourceIp=192.168.0.10,
DestIp=????,
TCP[
SourcePort=9999,
DestPort=80,
Flags=[SYN]
]
]
Incomplete SYN IP packet (note the ????
in the DestIP
field).
不完整的 SYN IP 数据包(注意 DestIP
字段中的 ????
)。
To get the IP address of www.example.com
, we need to use a service called DNS. DNS stands for Domain Name System and is the system responsible for translating human-readable names (such as www.example.com
) into IP addresses. Our computer creates a DNS request that includes the type of request (A
) and the domain name to resolve (www.example.com
). This DNS request is then encapsulated in a UDP datagram whose header contains a random source port (3333
from our assumptions) and the destination port (53
is DNS’s well-known port). This datagram is then placed inside an IP packet whose header has the source IP address (192.168.0.10
) and the destination IP address (8.8.8.8
). Note that the DNS server was configured beforehand in our computer so we already know what its IP address is.
要获取 www.example.com
的IP地址,我们需要使用称为DNS的服务。 DNS 代表域名系统,是负责将人类可读的名称(例如 www.example.com
)转换为 IP 地址的系统。我们的计算机创建一个 DNS 请求,其中包括请求类型 ( A
) 和要解析的域名 ( www.example.com
)。然后,此 DNS 请求被封装在 UDP 数据报中,其标头包含随机源端口(我们假设为 3333
)和目标端口( 53
是 DNS 的众所周知端口)。然后,该数据报被放置在 IP 数据包内,该数据包的标头具有源 IP 地址 ( 192.168.0.10
) 和目标 IP 地址 ( 8.8.8.8
)。请注意,我们的计算机中已预先配置了 DNS 服务器,因此我们已经知道其 IP 地址是什么。
We now want to send this IP packet but our computer doesn’t know where to send it. The computer looks at its route table to see which route matches the 8.8.8.8
IP address. The route table looks something like this:
我们现在想要发送这个 IP 数据包,但我们的计算机不知道将其发送到哪里。计算机查看其路由表以查看哪条路由与 8.8.8.8
IP 地址匹配。路由表看起来像这样:
Destination Netmask Gateway Interface
0.0.0.0 0.0.0.0 192.168.0.1 eth0
192.168.0.0 255.255.255.0 0.0.0.0 eth0
Route table of our computer.
我们计算机的路由表。
Our computer uses the longest prefix match to select who to send the packet to. In this case, it selects the first route which is our default gateway (192.168.0.1
). This means that the IP packet will be sent to our router and the router will take care of forwarding it to the next hop (which is hopefully closer to the DNS server). The routers in the path will keep forwarding the packet based on their routing tables until it reaches the DNS server (8.8.8.8
). This process happens every time our computer needs to send an IP packet and, in our case, it will always choose to send the packet to our default gateway (192.168.0.1
).
我们的计算机使用最长的前缀匹配来选择将数据包发送给谁。在本例中,它选择第一个路由,即我们的默认网关 ( 192.168.0.1
)。这意味着 IP 数据包将被发送到我们的路由器,并且路由器将负责将其转发到下一跳(希望更接近 DNS 服务器)。路径中的路由器将根据其路由表继续转发数据包,直到数据包到达 DNS 服务器 ( 8.8.8.8
)。每当我们的计算机需要发送 IP 数据包时,都会发生此过程,在我们的例子中,它总是选择将数据包发送到我们的默认网关 ( 192.168.0.1
)。
Now that the IP packet is ready, it is wrapped in an Ethernet frame. The Ethernet header contains the source MAC address (AA:AA:AA:AA:AA:AA
) and the destination MAC address (this would be the router’s MAC address in this case). To get the router’s MAC address, our computer looks in its ARP table to see if it has an entry to convert the router’s IP address (192.168.0.1
) to the router’s MAC address. Since the ARP cache is empty, we need to find out what is the MAC address before we can send the IP packet. This is how our incomplete Ethernet frame looks like:
现在 IP 数据包已准备就绪,它被包装在以太网帧中。以太网标头包含源 MAC 地址 ( AA:AA:AA:AA:AA:AA
) 和目标 MAC 地址(在本例中为路由器的 MAC 地址)。为了获取路由器的 MAC 地址,我们的计算机会在其 ARP 表中查找是否有将路由器的 IP 地址 ( 192.168.0.1
) 转换为路由器的 MAC 地址的条目。由于ARP缓存是空的,我们需要先找出MAC地址,然后才能发送IP数据包。这就是我们不完整的以太网帧的样子:
Ethernet[
SourceMac=AA:AA:AA:AA:AA:AA,
DestMac=????,
IP[
SourceIp=192.168.0.10,
DestIp=8.8.8.8,
UDP[
SourcePort=3333,
DestPort=53,
DNS[
Query=A,
Domain=www.example.com
]
]
]
]
Incomplete Ethernet frame for the DNS query (note the ????
in the DestMac
field).
DNS 查询的以太网帧不完整(注意 DestMac
字段中的 ????
)。
To convert IP addresses to MAC addresses, the ARP protocol is used. ARP stands for Address Resolution Protocol. The ARP packet contains a question asking who-has 192.168.0.1 tell 192.168.0.10
along with the source MAC address (AA:AA:AA:AA:AA:AA
), the destination MAC address (FF:FF:FF:FF:FF:FF
which is the broadcast address), the source IP address (192.168.0.10
), and the destination IP (192.168.0.1
which is the IP we’re asking about). The ARP packet is then wrapped in an Ethernet frame containing the source MAC address (AA:AA:AA:AA:AA:AA
) and for the destination MAC address, the broadcast address is used (FF:FF:FF:FF:FF:FF
). The frame is sent over our private network and looks something like this:
为了将 IP 地址转换为 MAC 地址,需要使用 ARP 协议。 ARP 代表地址解析协议。 ARP 数据包包含询问 who-has 192.168.0.1 tell 192.168.0.10
的问题以及源 MAC 地址 ( AA:AA:AA:AA:AA:AA
)、目标 MAC 地址( FF:FF:FF:FF:FF:FF
是广播地址)、源 IP 地址 ( 192.168.0.10
) 和目标IP( 192.168.0.1
这是我们要询问的 IP)。然后,ARP 数据包被包装在包含源 MAC 地址 ( AA:AA:AA:AA:AA:AA
) 的以太网帧中,对于目标 MAC 地址,使用广播地址 ( FF:FF:FF:FF:FF:FF
)。该帧通过我们的专用网络发送,如下所示:
Ethernet[
SourceMac=AA:AA:AA:AA:AA:AA,
DestMac=FF:FF:FF:FF:FF:FF,
ARP[
Type=Request,
SourceIp=192.168.0.10,
DestIp=192.168.0.1,
SourceMac=AA:AA:AA:AA:AA:AA,
DestMac=FF:FF:FF:FF:FF:FF
]
]
ARP packet to find out our router’s MAC address.
ARP 数据包用于查找路由器的 MAC 地址。
There is something worth noting at this point. This is the first interaction that our computer has had with the network!
此时有一点值得注意。这是我们的计算机与网络的第一次交互!
Since the broadcast MAC address (FF:FF:FF:FF:FF:FF
) was used, this frame will reach every node on our private network. Every node (except for our router) will end up discarding the packet since the destination IP address (192.168.0.1
) is not their IP.
由于使用了广播 MAC 地址 ( FF:FF:FF:FF:FF:FF
),因此该帧将到达我们专用网络上的每个节点。每个节点(除了我们的路由器)最终都会丢弃数据包,因为目标 IP 地址 ( 192.168.0.1
) 不是它们的 IP。
When our router receives this packet, it will see that 192.168.0.10
is asking for its MAC address. It can also see in the ARP packet the source MAC address of our computer. The router saves this information in its ARP table (192.168.0.10 -> AA:AA:AA:AA:AA:AA
) and creates an ARP reply saying 192.168.0.1 is-at BB:BB:BB:BB:BB:BB
. This ARP reply is then wrapped in an Ethernet frame with the source MAC address (BB:BB:BB:BB:BB:BB
) and destination MAC address (AA:AA:AA:AA:AA:AA
). The Ethernet frame is now sent over the network. One thing to note here is that the destination MAC address is no longer the broadcast MAC address so only our computer will process it. From now on, our router will be able to convert our computer’s IP address (192.168.0.10
) to its MAC address (AA:AA:AA:AA:AA:AA
) by referring to its ARP cache. The Ethernet frame containing this reply looks something like this:
当我们的路由器收到这个数据包时,它会看到 192.168.0.10
正在询问其MAC地址。它还可以在ARP数据包中看到我们计算机的源MAC地址。路由器将此信息保存在其 ARP 表 ( 192.168.0.10 -> AA:AA:AA:AA:AA:AA
) 中,并创建一个 ARP 回复 192.168.0.1 is-at BB:BB:BB:BB:BB:BB
。然后,该 ARP 回复将被封装在具有源 MAC 地址 ( BB:BB:BB:BB:BB:BB
) 和目标 MAC 地址 ( AA:AA:AA:AA:AA:AA
) 的以太网帧中。以太网帧现在通过网络发送。这里需要注意的一件事是,目标 MAC 地址不再是广播 MAC 地址,因此只有我们的计算机会处理它。从现在开始,我们的路由器将能够通过引用其 ARP 缓存将计算机的 IP 地址( 192.168.0.10
)转换为其 MAC 地址( AA:AA:AA:AA:AA:AA
)。包含此回复的以太网帧如下所示:
Ethernet[
SourceMac=BB:BB:BB:BB:BB:BB,
DestMac=AA:AA:AA:AA:AA:AA,
ARP[
Type=Reply,
SourceIp=192.168.0.1,
DestIp=192.168.0.10,
SourceMac=BB:BB:BB:BB:BB:BB,
DestMac=AA:AA:AA:AA:AA:AA
]
]
ARP reply where our router tells its MAC address to our computer.
ARP 回复,我们的路由器将其 MAC 地址告诉我们的计算机。
Our computer receives the Ethernet frame, sees the ARP reply and saves the MAC address of our router in its ARP table (192.168.0.1 -> BB:BB:BB:BB:BB:BB
). From now on, any time our computer needs to convert our router’s IP address (192.168.0.1
) to its MAC address (BB:BB:BB:BB:BB:BB
), it simply needs to refer to its ARP cache. We’re making progress! We now have the MAC address of our router, which we need to send the IP packet with the DNS query to get the IP of www.example.com
, which we need to send a TCP SYN
packet, to establish a TCP connection over port 80
, which we need to send the HTTP request.
我们的计算机接收以太网帧,查看 ARP 回复并将路由器的 MAC 地址保存在其 ARP 表中 ( 192.168.0.1 -> BB:BB:BB:BB:BB:BB
)。从现在开始,每当我们的计算机需要将路由器的 IP 地址 ( 192.168.0.1
) 转换为其 MAC 地址 ( BB:BB:BB:BB:BB:BB
) 时,它只需要引用其 ARP 缓存即可。我们正在进步!现在我们有了路由器的 MAC 地址,我们需要发送带有 DNS 查询的 IP 数据包来获取 www.example.com
的 IP,我们需要发送 TCP SYN
数据包,以通过端口建立 TCP 连接 80
,我们需要发送 HTTP 请求。
Since our computer now knows the MAC address of the router, it fills in the blanks of the Ethernet frame containing our DNS query and sends it over the network to (BB:BB:BB:BB:BB:BB
). This happens with every Ethernet frame that needs to be sent to our router. The frame looks something like this:
由于我们的计算机现在知道路由器的 MAC 地址,因此它会填充包含 DNS 查询的以太网帧的空白,并将其通过网络发送到 ( BB:BB:BB:BB:BB:BB
)。每个需要发送到路由器的以太网帧都会发生这种情况。框架看起来像这样:
Ethernet[
SourceMac=AA:AA:AA:AA:AA:AA,
DestMac=BB:BB:BB:BB:BB:BB,
IP[
SourceIp=192.168.0.10,
DestIp=8.8.8.8,
UDP[
SourcePort=3333,
DestPort=53,
DNS[
Query=A,
Domain=www.example.com
]
]
]
]
Complete Ethernet frame for the DNS query.
DNS 查询的完整以太网帧。
One thing to note is that the DestIp
field is not the router’s IP address; it’s still 8.8.8.8
.
需要注意的一件事是 DestIp
字段不是路由器的IP地址;仍然是 8.8.8.8
。
The router receives this frame and looks at the destination IP (8.8.8.8
) in the IP header. It also uses the longest prefix match to select where to forward this packet and ends up selecting its default Gateway (51.0.0.1
). This decision is made every time the router needs to forward a packet to an IP address in the public Internet such as 8.8.8.8
(and later 93.184.216.34
).
路由器接收此帧并查看 IP 标头中的目标 IP ( 8.8.8.8
)。它还使用最长的前缀匹配来选择转发此数据包的位置,并最终选择其默认网关 ( 51.0.0.1
)。每当路由器需要将数据包转发到公共互联网中的 IP 地址(例如 8.8.8.8
(以及后来的 93.184.216.34
))时,就会做出此决定。
Based on our assumptions our router is also a NAT. This means that our router needs to translate the packet before it can be forwarded. NAT stands for Network Address Translation. It is widely deployed to have multiple devices share a single public IP address. Our internal (or private) network uses private IP addresses (192.168.0.1
and 192.168.0.10
) but the public Internet uses public IP addresses. When we need to send a packet to the public Internet, the NAT takes care of replacing the private IP address with the public IP address (51.0.0.20
). The NAT uses 5 values to identify a connection: protocol (UDP
/ TCP
), source IP, internal source port, destination IP and external source port. The external source port is chosen randomly to make sure the connection identifier is unique. Based on our assumptions, the router decides to use port 10000
. The entry in the NAT table looks something like this:
根据我们的假设,我们的路由器也是 NAT。这意味着我们的路由器需要先转换数据包才能转发。 NAT 代表网络地址转换。它被广泛部署,让多个设备共享一个公共 IP 地址。我们的内部(或专用)网络使用专用 IP 地址( 192.168.0.1
和 192.168.0.10
),但公共互联网使用公共 IP 地址。当我们需要将数据包发送到公共互联网时,NAT 负责将私有 IP 地址替换为公共 IP 地址 ( 51.0.0.20
)。 NAT 使用 5 个值来标识连接:协议 ( UDP
/ TCP
)、源 IP、内部源端口、目标 IP 和外部源端口。外部源端口是随机选择的,以确保连接标识符是唯一的。根据我们的假设,路由器决定使用端口 10000
。 NAT 表中的条目如下所示:
UDP 192.168.0.10 3333 -> 8.8.8.8 10000
NAT table. Note that the destination port (53
) is not used to identify the connection.
NAT 表。请注意,目标端口 ( 53
) 不用于标识连接。
Our router uses the information in the NAT table to replace the source IP address of the packet (192.168.0.10
) with the public IP address (51.0.0.20
), and the internal source port (3333
) with the external source port (10000
). This makes that IP packet routable in the public Internet. Our router performs this translation for any packet that needs to go out to the public Internet including TCP/IP packets. We’ll call this process internal-to-external translation.
我们的路由器使用 NAT 表中的信息将数据包的源 IP 地址 ( 192.168.0.10
) 替换为公共 IP 地址 ( 51.0.0.20
),并将内部源端口 ( 3333
) 替换为外部源端口 ( 10000
)。这使得该 IP 数据包可以在公共 Internet 中路由。我们的路由器对任何需要发送到公共互联网的数据包(包括 TCP/IP 数据包)执行此转换。我们将这个过程称为内部到外部的翻译。
Our router wraps the packet in a new Ethernet frame with the source MAC address of CC:CC:CC:CC:CC:CC
, and a destination MAC address of DD:DD:DD:DD:DD:DD
(we assumed this value was already cached so there’s no need for ARP). Every packet that our router forwards to the public Internet goes through the same process so we won’t bring this up again. The Ethernet frame ends up looking something like this:
我们的路由器将数据包包装在一个新的以太网帧中,源 MAC 地址为 CC:CC:CC:CC:CC:CC
,目标 MAC 地址为 DD:DD:DD:DD:DD:DD
(我们假设该值已被缓存,因此不需要 ARP)。我们的路由器转发到公共互联网的每个数据包都会经历相同的过程,因此我们不会再提起这个问题。以太网帧最终看起来像这样:
Ethernet[
SourceMac=CC:CC:CC:CC:CC:CC,
DestMac=DD:DD:DD:DD:DD:DD,
IP[
SourceIp=51.0.0.20,
DestIp=8.8.8.8,
UDP[
SourcePort=10000,
DestPort=53,
DNS[
Query=A,
Domain=www.example.com
]
]
]
]
Publicly routable packet with DNS query (note the change in SourceIp
and SourcePort
).
具有 DNS 查询的公共可路由数据包(请注意 SourceIp
和 SourcePort
中的更改)。
The Ethernet frame is sent to the default gateway which is most likely a router owned by our ISP and it is up to the ISP to get our packet to 8.8.8.8
.
以太网帧被发送到默认网关,该网关很可能是我们的 ISP 拥有的路由器,并且由 ISP 将我们的数据包发送到 8.8.8.8
。
Once our packet reaches 8.8.8.8
(Google’s DNS server), the server takes a look at the query (A
for www.example.com
) and searches its cache. We’re assuming that the cache entry exists, so it knows that www.example.com
maps to 93.184.216.34
. The DNS server creates a new DNS response message containing this information as the answer to the query. The response is wrapped in a UDP datagram with source port 53
and destination port 10000
. The UDP datagram is then wrapped in an IP packet with source IP 8.8.8.8
and destination IP 51.0.0.20
(our public IP). The packet is finally wrapped in an Ethernet frame (we’ll ignore this part) and sent through the network. The IP packet ends up looking like this:
一旦我们的数据包到达 8.8.8.8
(Google 的 DNS 服务器),服务器就会查看查询( A
代表 www.example.com
)并搜索其缓存。我们假设缓存条目存在,因此它知道 www.example.com
映射到 93.184.216.34
。 DNS 服务器创建包含此信息的新 DNS 响应消息作为查询的答案。响应封装在具有源端口 53
和目标端口 10000
的 UDP 数据报中。然后,UDP 数据报被包装在一个 IP 数据包中,其中源 IP 8.8.8.8
和目标 IP 51.0.0.20
(我们的公共 IP)。数据包最终被包装在以太网帧中(我们将忽略这部分)并通过网络发送。 IP 数据包最终看起来像这样:
IP[
SourceIp=8.8.8.8,
DestIp=51.0.0.20,
UDP[
SourcePort=53,
DestPort=10000,
DNS[
Answer=93.184.216.34,
Domain=www.example.com
]
]
]
IP packet containing the DNS reply.
包含 DNS 回复的 IP 数据包。
The packet traverses the network and eventually reaches our router. Our router needs to translate this packet before it forwards it into our private network. The router looks at the protocol (UDP
), source IP (8.8.8.8
) and the destination port (10000
) to find an entry in the NAT table with those values. With the values from the table, the router translates the destination IP to be our computer’s IP (192.168.0.10
) and the destination port to be our computer’s source port (3333
). This makes that IP packet routable in our private network. The same process occurs for any packet coming from the public Internet including TCP/IP packets (only packets whose properties can be found in the NAT table are translated, the others are dropped). We’ll call this process external-to-internal translation. After this, the router wraps the packet in an Ethernet frame with source MAC BB:BB:BB:BB:BB:BB
and destination MAC AA:AA:AA:AA:AA:AA
and sends it over the private network (this happens every time our router forwards a packet to our computer so we won’t bring it up again). The Ethernet frame with the translated IP packet looks something like this:
数据包穿过网络并最终到达我们的路由器。我们的路由器需要先转换此数据包,然后再将其转发到我们的专用网络。路由器查看协议 ( UDP
)、源 IP ( 8.8.8.8
) 和目标端口 ( 10000
),以在 NAT 表中查找具有这些值的条目。根据表中的值,路由器将目标 IP 转换为我们计算机的 IP ( 192.168.0.10
),将目标端口转换为我们计算机的源端口 ( 3333
)。这使得该 IP 数据包可以在我们的专用网络中路由。对于来自公共 Internet 的任何数据包(包括 TCP/IP 数据包)都会发生相同的过程(仅转换其属性可以在 NAT 表中找到的数据包,其他数据包将被丢弃)。我们将这个过程称为外部到内部的翻译。此后,路由器将数据包包装在带有源 MAC BB:BB:BB:BB:BB:BB
和目标 MAC AA:AA:AA:AA:AA:AA
的以太网帧中,并通过专用网络发送(每次我们的路由器将数据包转发到我们的计算机时都会发生这种情况,因此我们不会将数据包带入以太网帧)又起来了)。带有转换后的 IP 数据包的以太网帧如下所示:
Ethernet[
SourceMac=BB:BB:BB:BB:BB:BB,
DestMac=AA:AA:AA:AA:AA:AA,
IP[
SourceIp=8.8.8.8,
DestIp=192.168.0.10,
UDP[
SourcePort=53,
DestPort=3333,
DNS[
Answer=93.184.216.34,
Domain=www.example.com
]
]
]
]
Privately routable packet containing the DNS reply (note the change in DestIp
and DestPort
).
包含 DNS 回复的私有可路由数据包(请注意 DestIp
和 DestPort
中的更改)。
With the IP address of www.example.com
, our computer fills in the destination IP in our incomplete SYN
packet. The IP header is wrapped in an Ethernet frame and sent through the private network. The Ethernet frame looks something like this:
使用 www.example.com
的IP地址,我们的计算机将目标IP填入不完整的 SYN
数据包中。 IP 标头封装在以太网帧中并通过专用网络发送。以太网帧看起来像这样:
Ethernet[
SourceMac=AA:AA:AA:AA:AA:AA,
DestMac=BB:BB:BB:BB:BB:BB,
IP[
SourceIp=192.168.0.10,
DestIp=93.184.216.34,
TCP[
SourcePort=9999,
DestPort=80,
Flags=[SYN]
]
]
]
Privately routable packet containing the TCP SYN packet.
包含 TCP SYN 数据包的私有可路由数据包。
Our router receives the packet and extracts the protocol (TCP
), the source IP (192.168.0.10
), the source port (9999
), the destination IP (93.184.216.34
) and generates a random number to be used as the external source port (15000
from the assumptions). These values identify the TCP connection and are saved in the router’s NAT table. Our router can reference the NAT table to identify packets that need to be translated and what values to use for the translation. The entry in the NAT table looks something like this:
我们的路由器接收数据包并提取协议( TCP
)、源IP( 192.168.0.10
)、源端口( 9999
)、目标IP( 93.184.216.34
)并生成一个随机数用作外部源端口(来自假设的 15000
)。这些值标识 TCP 连接并保存在路由器的 NAT 表中。我们的路由器可以参考 NAT 表来识别需要转换的数据包以及用于转换的值。 NAT 表中的条目如下所示:
TCP 192.168.0.10 9999 -> 93.184.216.34 15000
Our router uses our public IP address (51.0.0.20
) to replace the source IP and the port generated in the previous step (15000
) to replace the source port. It then wraps the translated IP packet in an Ethernet frame and sends it over the network. The Ethernet frame looks something like this:
我们的路由器使用我们的公共IP地址( 51.0.0.20
)来替换源IP,并使用上一步中生成的端口( 15000
)来替换源端口。然后它将转换后的 IP 数据包包装在以太网帧中并通过网络发送。以太网帧看起来像这样:
Ethernet[
SourceMac=CC:CC:CC:CC:CC:CC,
DestMac=DD:DD:DD:DD:DD:DD,
IP[
SourceIp=51.0.0.20,
DestIp=93.184.216.34,
TCP[
SourcePort=15000,
DestPort=80,
Flags=[SYN]
]
]
]
Publicly routable SYN segment (note the changes to SourceIp
and SourcePort
).
公共可路由 SYN 段(注意 SourceIp
和 SourcePort
的更改)。
When the packet reaches 93.184.216.34
(the IP address of www.example.com
), the server looks at the destination port of the TCP header (80
) and checks if an application is listening on that port. Since there is an HTTP server running on that port, the server needs to reply with a SYN
/ACK
. The server creates a TCP
segment and sets its source port to 80
, the destination port to 15000
(the source port of the SYN
packet that was just received), and SYN
/ACK
for the flags. It then wraps the segment in an IP packet with source IP of 93.184.216.34
and destination IP of 51.0.0.20
. Finally, it wraps the IP packet in an Ethernet frame (we’re going to ignore this part). The packet is then sent out to the network and looks something like this:
当数据包到达 93.184.216.34
( www.example.com
的IP地址)时,服务器查看TCP标头的目标端口( 80
)并检查应用程序是否正在侦听该端口。由于该端口上运行着一个 HTTP 服务器,因此服务器需要回复 SYN
/ ACK
。服务器创建一个 TCP
段,并将其源端口设置为 80
,目标端口设置为 15000
(刚刚收到的 SYN
数据包的源端口),并将 SYN
/ ACK
设置为 SYN
/ ACK
旗帜。然后,它将该段包装在 IP 数据包中,源 IP 为 93.184.216.34
,目标 IP 为 51.0.0.20
。最后,它将 IP 数据包包装在以太网帧中(我们将忽略这部分)。然后数据包被发送到网络,看起来像这样:
IP[
SourceIp=93.184.216.34,
DestIp=51.0.0.20,
TCP[
SourcePort=80,
DestPort=15000,
Flags=[SYN, ACK]
]
]
IP packet containing the TCP SYN / ACK.
包含 TCP SYN/ACK 的 IP 数据包。
When the packet reaches our router, it performs an external-to-internal translation. The translated packet is wrapped in an Ethernet frame and sent over the private network. The Ethernet frame looks something like this:
当数据包到达我们的路由器时,它会执行外部到内部的转换。转换后的数据包封装在以太网帧中并通过专用网络发送。以太网帧看起来像这样:
Ethernet[
SourceMac=BB:BB:BB:BB:BB:BB,
DestMac=AA:AA:AA:AA:AA:AA,
IP[
SourceIp=93.184.216.34,
DestIp=192.168.0.10,
TCP[
SourcePort=80,
DestPort=9999,
Flags=[SYN, ACK]
]
]
]
Privately routable packet containing the TCP SYN / ACK.
包含 TCP SYN/ACK 的私有可路由数据包。
Our computer looks at the destination port (9999
) and the TCP flags (SYN
/ACK
) and checks the state of this connection. The only thing missing to establish this connection is to send an ACK
back to the server (93.184.216.34
). Our computer creates a new TCP segment with source port 9999
, destination port 80
and ACK
as its only flag. This segment is then wrapped in an IP packet with source IP 192.168.0.10
and destination IP 93.184.216.34
. The IP packet is wrapped in an Ethernet frame and sent over the private network. The Ethernet frame looks something like this:
我们的计算机查看目标端口 ( 9999
) 和 TCP 标志 ( SYN
/ ACK
) 并检查此连接的状态。建立此连接唯一缺少的是将 ACK
发送回服务器 ( 93.184.216.34
)。我们的计算机创建一个新的 TCP 段,其中源端口 9999
、目标端口 80
和 ACK
作为其唯一标志。然后,该段被包装在具有源 IP 192.168.0.10
和目标 IP 93.184.216.34
的 IP 数据包中。 IP 数据包封装在以太网帧中并通过专用网络发送。以太网帧看起来像这样:
Ethernet[
SourceMac=AA:AA:AA:AA:AA:AA,
DestMac=BB:BB:BB:BB:BB:BB,
IP[
SourceIp=192.168.0.10,
DestIp=93.184.216.34,
TCP[
SourcePort=9999,
DestPort=80,
Flags=[ACK]
]
]
]
Privately routable packet containing the ACK to complete the three-way handshake.
包含 ACK 的私有可路由数据包,用于完成三向握手。
Our router receives this frame and uses the information in the NAT table to perform an internal-to-external translation. Then, it wraps the translated IP packet in an Ethernet frame and sends it over the public network. The Ethernet frame looks something like this:
我们的路由器接收此帧并使用 NAT 表中的信息来执行内部到外部的转换。然后,它将转换后的 IP 数据包包装在以太网帧中,并通过公共网络发送。以太网帧看起来像这样:
Ethernet[
SourceMac=CC:CC:CC:CC:CC:CC,
DestMac=DD:DD:DD:DD:DD:DD,
IP[
SourceIp=50.0.0.20,
DestIp=93.184.216.34,
TCP[
SourcePort=15000,
DestPort=80,
Flags=[ACK]
]
]
]
Publicly routable packet containing the ACK to complete the three-way handshake.
包含 ACK 的公共可路由数据包,用于完成三向握手。
The packet traverses the Internet until it gets to 93.184.216.34
. The server uses the source port (15000
) and the source IP (50.0.0.20
) to check the connection state and marks the connection as ESTABLISHED. Note that the server doesn’t return an ACK
for the ACK
it just received.
数据包遍历 Internet 直到到达 93.184.216.34
。服务器使用源端口 ( 15000
) 和源 IP ( 50.0.0.20
) 检查连接状态并将连接标记为 ESTABLISHED。请注意,服务器不会为刚刚收到的 ACK
返回 ACK
。
Our computer is now ready to send the actual HTTP request. It wraps the HTTP request in a TCP
segment with source port 9999
, destination port 80
and sets the flags to ACK
/PUSH
. This TCP segment is then wrapped in an IP packet with source IP 192.168.0.10
and destination IP 93.184.216.34
. Then, it wraps the IP packet in an Ethernet frame and sends it through the private network. The frame looks something like this:
我们的计算机现在已准备好发送实际的 HTTP 请求。它将 HTTP 请求包装在 TCP
段中,源端口为 9999
,目标端口为 80
,并将标志设置为 ACK
/ PUSH
。然后,该 TCP 段被包装在具有源 IP 192.168.0.10
和目标 IP 93.184.216.34
的 IP 数据包中。然后,它将 IP 数据包包装在以太网帧中并通过专用网络发送。框架看起来像这样:
Ethernet[
SourceMac=AA:AA:AA:AA:AA:AA,
DestMac=BB:BB:BB:BB:BB:BB,
IP[
SourceIp=192.168.0.10,
DestIp=93.184.216.34,
TCP[
SourcePort=9999,
DestPort=80,
Flags=[ACK, PUSH],
HTTP[
GET / HTTP/1.1
Host: www.example.com
...
]
]
]
]
Privately routable packet containing the HTTP request.
包含 HTTP 请求的私有可路由数据包。
Our router receives the frame and does an internal-to-external translation to the IP packet. It then wraps the translated packet in an Ethernet frame and sends it over the public network. The Ethernet frame looks something like this:
我们的路由器接收帧并对 IP 数据包进行内部到外部的转换。然后,它将转换后的数据包包装在以太网帧中,并通过公共网络发送。以太网帧看起来像这样:
Ethernet[
SourceMac=CC:CC:CC:CC:CC:CC,
DestMac=DD:DD:DD:DD:DD:DD,
IP[
SourceIp=50.0.0.20,
DestIp=93.184.216.34,
TCP[
SourcePort=15000,
DestPort=80,
Flags=[ACK, PUSH],
HTTP[
GET / HTTP/1.1
Host: www.example.com
...
]
]
]
]
Publicly routable packet containing HTTP request.
包含 HTTP 请求的公共可路由数据包。
The packet reaches 93.184.216.3
(www.example.com
) and the server uses the source IP (51.0.0.20
) and source port (15000
) to verify that the connection exists and is ESTABLISHED. The PUSH
flag in the TCP segment instructs the server to send the body of the TCP segment (the HTTP request) to the application listening on port 80
(the HTTP server). The HTTP server processes the HTTP request and generates an HTTP response. An HTTP response from www.example.com
looks something like this:
数据包到达 93.184.216.3
( www.example.com
),服务器使用源 IP ( 51.0.0.20
) 和源端口 ( 15000
) 来验证连接是否存在且已建立。 TCP 段中的 PUSH
标志指示服务器将 TCP 段的主体(HTTP 请求)发送到侦听端口 80
的应用程序(HTTP 服务器)。 HTTP 服务器处理 HTTP 请求并生成 HTTP 响应。来自 www.example.com
的 HTTP 响应看起来像这样:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: max-age=604800
Content-Type: text/html
Date: Sat, 11 Aug 2018 20:45:46 GMT
Etag: "1541025663"
Expires: Sat, 18 Aug 2018 20:45:46 GMT
Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
Server: ECS (oxr/830D)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 606
<!doctype html>
<html>
...
</html>
Sample HTTP response from www.example.com
(snipped almost all of the body).
来自 www.example.com
的 HTTP 响应示例(截取了几乎所有正文)。
Note: The server should have sent and ACK to acknowledge that this TCP segment was received. However, this ACK can also be sent along with the HTTP response, so in the interest of not being even more repetitive, we’ll assume this is the case.
注意:服务器应该发送 ACK 来确认已收到该 TCP 段。然而,这个 ACK 也可以与 HTTP 响应一起发送,因此为了避免更加重复,我们假设情况就是如此。
The HTTP response is wrapped in a TCP segment with source port 80
, destination port 15000
and flags ACK
/PUSH
. Then, the TCP segment is wrapped in an IP packet with source IP 93.184.216.34
and destination IP 50.0.0.20
. The packet is then wrapped in an Ethernet frame (that we are also going to ignore) and sent through the public network. The IP packet looks something like:
HTTP 响应包装在带有源端口 80
、目标端口 15000
和标志 ACK
/ PUSH
的 TCP 段中。然后,TCP 段被包装在具有源 IP 93.184.216.34
和目标 IP 50.0.0.20
的 IP 数据包中。然后,数据包被包装在以太网帧中(我们也将忽略它)并通过公共网络发送。 IP 数据包看起来类似于:
IP[
SourceIp=93.184.216.34,
DestIp=50.0.0.20,
TCP[
SourcePort=80,
DestPort=15000,
Flags=[ACK, PUSH],
HTTP[
HTTP/1.1 200 OK
Accept-Ranges: bytes
...
<!doctype html>
...
]
]
]
IP packet containing the HTTP response.
包含 HTTP 响应的 IP 数据包。
Our router receives the packet and performs an external-to-internal translation. After that, the IP packet is wrapped with an Ethernet frame and sent over the private network. The Ethernet frame looks something like this:
我们的路由器接收数据包并执行外部到内部的转换。之后,IP 数据包用以太网帧封装并通过专用网络发送。以太网帧看起来像这样:
Ethernet[
SourceMac=BB:BB:BB:BB:BB:BB,
DestMac=AA:AA:AA:AA:AA:AA,
IP[
SourceIp=93.184.216.34,
DestIp=192.168.0.10,
TCP[
SourcePort=80,
DestPort=9999,
Flags=[ACK, PUSH],
HTTP[
HTTP/1.1 200 OK
Accept-Ranges: bytes
...
<!doctype html>
...
]
]
]
]
Privately routable packet with the HTTP response.
带有 HTTP 响应的私有可路由数据包。
Our computer receives the packet and looks up the connection information. The PUSH
flag instructs our computer to send the TCP body (the HTTP response) to the application that opened the connection (our web browser). Our web browser now has the HTTP response and can use it to render the web page. From the networking side, however, we’re not done. The server doesn’t know that we received the TCP segment since we haven’t acknowledged it (sent an ACK back). Since the browser is not going to send more requests to www.example.com
, it will also close the connection. These two actions can be combined into one by sending the ACK
and the FIN
flags in the same TCP segment (we’re going to assume this happened to avoid even more repetition).
我们的计算机收到数据包并查找连接信息。 PUSH
标志指示我们的计算机将 TCP 正文(HTTP 响应)发送到打开连接的应用程序(我们的 Web 浏览器)。我们的 Web 浏览器现在有了 HTTP 响应,可以使用它来呈现网页。然而,从网络方面来看,我们还没有完成。服务器不知道我们收到了 TCP 段,因为我们还没有确认它(发回 ACK)。由于浏览器不会向 www.example.com
发送更多请求,因此它也会关闭连接。通过在同一 TCP 段中发送 ACK
和 FIN
标志,可以将这两个操作合并为一个(我们假设发生这种情况是为了避免更多重复)。
Our computer creates a new TCP segment with source port 9999
, destination port 80
and FIN
/ACK
as its flags. It places this segment in an IP packet with source IP 192.168.0.10
and destination IP 93.184.216.34
. The IP packet is wrapped with an Ethernet frame and is sent over the network. The Ethernet frame looks something like this:
我们的计算机创建一个新的 TCP 段,其中源端口 9999
、目标端口 80
和 FIN
/ ACK
作为其标志。它将这个段放入一个带有源 IP 192.168.0.10
和目标 IP 93.184.216.34
的 IP 数据包中。 IP 数据包用以太网帧封装并通过网络发送。以太网帧看起来像这样:
Ethernet[
SourceMac=AA:AA:AA:AA:AA:AA,
DestMac=BB:BB:BB:BB:BB:BB,
IP[
SourceIp=192.168.0.10,
DestIp=93.184.216.34,
TCP[
SourcePort=9999,
DestPort=80,
Flags=[ACK, FIN]
]
]
]
Privately routable packet containing the ACK for the HTTP response and the FIN to close the TCP connection.
私有可路由数据包,包含 HTTP 响应的 ACK 和关闭 TCP 连接的 FIN。
The router gets this frame and performs an internal-to-external translation. Then, it wraps the IP packet in an Ethernet frame and sends the frame to the public network. The frame looks something like this:
路由器获取此帧并执行内部到外部的转换。然后,它将 IP 数据包包装在以太网帧中,并将该帧发送到公共网络。框架看起来像这样:
Ethernet[
SourceMac=CC:CC:CC:CC:CC:CC,
DestMac=DD:DD:DD:DD:DD:DD,
IP[
SourceIp=50.0.0.20,
DestIp=93.184.216.34,
TCP[
SourcePort=15000,
DestPort=80,
Flags=[ACK, FIN]
]
]
]
Publicly routable packet with the ACK for the HTTP response and the FIN to close the TCP connection.
公共可路由数据包,带有用于 HTTP 响应的 ACK 和用于关闭 TCP 连接的 FIN。
When the server receives this packet, it now knows that the HTTP response was received. From the flags, it can also tell that our computer wants to close the connection. The server creates a new TCP segment with source port 80
, destination port 15000
and flags FIN
/ACK
. It wraps this TCP segment in an IP packet with source IP 93.184.216.34
and destination IP 50.0.0.20
. The IP packet is sent over the network. The IP packet looks something like this:
当服务器收到此数据包时,它现在知道已收到 HTTP 响应。从标志中,它还可以得知我们的计算机想要关闭连接。服务器创建一个新的 TCP 段,其中包含源端口 80
、目标端口 15000
和标志 FIN
/ ACK
。它将这个 TCP 段包装在一个带有源 IP 93.184.216.34
和目标 IP 50.0.0.20
的 IP 数据包中。 IP 数据包通过网络发送。 IP 数据包看起来像这样:
IP[
SourceIp=93.184.216.34,
DestIp=50.0.0.20,
TCP[
SourcePort=80,
DestPort=15000,
Flags=[ACK, FIN]
]
]
IP packet containing the FIN to close the connection.
包含用于关闭连接的 FIN 的 IP 数据包。
When our router receives the packet, it performs an external-to-internal translation and then wraps the packet in an Ethernet frame. It then sends the frame through our private network. The frame looks something like this:
当我们的路由器收到数据包时,它会执行外部到内部的转换,然后将数据包包装在以太网帧中。然后它通过我们的专用网络发送帧。框架看起来像这样:
Ethernet[
SourceMac=BB:BB:BB:BB:BB:BB,
DestMac=AA:AA:AA:AA:AA:AA,
IP[
SourceIp=93.184.216.34,
DestIp=192.168.0.10,
TCP[
SourcePort=80,
DestPort=9999,
Flags=[ACK, FIN]
]
]
]
Privately routable packet containing the FIN to close the connection.
包含用于关闭连接的 FIN 的私有可路由数据包。
Our computer receives this packet and finds a FIN in the flags. The connection is now closed, all that remains is for our computer to send an acknowledgement to the server that it received the FIN
/ACK
packet. It creates a TCP segment with source port 9999
and destination port 80
. The segment is wrapped in an IP packet with source IP 192.168.0.10
and destination IP 93.184.216.34
. The IP packet is wrapped in an Ethernet frame and sent over the private network. The frame looks something like this:
我们的计算机收到此数据包并在标志中发现 FIN。现在连接已关闭,剩下的就是我们的计算机向服务器发送一条确认消息,确认它收到了 FIN
/ ACK
数据包。它创建一个带有源端口 9999
和目标端口 80
的 TCP 段。该段被包装在一个带有源 IP 192.168.0.10
和目标 IP 93.184.216.34
的 IP 数据包中。 IP 数据包封装在以太网帧中并通过专用网络发送。框架看起来像这样:
Ethernet[
SourceMac=AA:AA:AA:AA:AA:AA,
DestMac=BB:BB:BB:BB:BB:BB,
IP[
SourceIp=192.168.0.10,
DestIp=93.184.216.34,
TCP[
SourcePort=9999,
DestPort=80,
Flags=[ACK]
]
]
]
Privately routable packet containing last ACK to acknowledge that the connection has been closed.
包含最后一个 ACK 的私有可路由数据包,用于确认连接已关闭。
The router receives this frame and performs an internal-to-external translation. The IP packet is wrapped in an Ethernet frame sent over the public network. The Ethernet frame looks something like this:
路由器接收该帧并执行内部到外部的转换。 IP 数据包封装在通过公共网络发送的以太网帧中。以太网帧看起来像这样:
Ethernet[
SourceMac=CC:CC:CC:CC:CC:CC,
DestMac=DD:DD:DD:DD:DD:DD,
IP[
SourceIp=50.0.0.20,
DestIp=93.184.216.34,
TCP[
SourcePort=15000,
DestPort=80,
Flags=[ACK]
]
]
]
Publicly routable packet with translated packet with last ACK.
公共可路由数据包,其中包含带有最后 ACK 的已转换数据包。
When the server gets this packet, it looks at the flags and confirms that our computer got the FIN TCP segment.
当服务器收到此数据包时,它会查看标志并确认我们的计算机已收到 FIN TCP 段。
Conclusion 结论
Wow, that was a long post! I think we can all agree that a lot happens at the network layer from the time you type a URL in the browser and press enter until you get to see your web page. There are a few important things to call out though:
哇,那是一篇很长的文章!我想我们都同意,从您在浏览器中输入 URL 并按 Enter 直到看到网页,网络层发生了很多事情。不过,有一些重要的事情需要注意:
- This was just one HTTP request! Usually, a page that has external scripts, images, stylesheets, etc, makes tens or hundreds of requests!
这只是一个 HTTP 请求!通常,具有外部脚本、图像、样式表等的页面会发出数十或数百个请求! - With only one request, we were able to see the value of caching. We only had to ask for the MAC address of the router once and then we were able to fetch that MAC address from the cache. If we had made more requests, DNS caching would have also played a role since we would have cached the IP address of
www.example.com
and wouldn’t have had to ask our DNS server for it.
仅通过一个请求,我们就能够看到缓存的价值。我们只需询问一次路由器的 MAC 地址,然后就可以从缓存中获取该 MAC 地址。如果我们发出更多请求,DNS 缓存也会发挥作用,因为我们会缓存www.example.com
的 IP 地址,而不必向我们的 DNS 服务器询问。 - Caching plays a big role in HTTP as well. If our browser had cached this page before, we wouldn’t have had to make any network calls!
缓存在 HTTP 中也发挥着重要作用。如果我们的浏览器之前缓存了这个页面,我们就不必进行任何网络调用! - There is some overhead while establishing the TCP connection. HTTP clients try to keep the connection alive (with the
Connection: Keep-Alive
HTTP header) to avoid this overhead and reuse the same connection. A problem with this header is that HTTP clients can only make one request a time (per TCP connection). HTTP/2 and QUIC solve this problem by multiplexing the connection.
建立 TCP 连接时会产生一些开销。 HTTP 客户端尝试保持连接处于活动状态(使用Connection: Keep-Alive
HTTP 标头)以避免这种开销并重用相同的连接。此标头的一个问题是 HTTP 客户端一次只能发出一个请求(每个 TCP 连接)。 HTTP/2 和 QUIC 通过复用连接解决了这个问题。
Thanks for reading! I hope you enjoyed it and learned something!
谢谢阅读!我希望你喜欢它并学到一些东西!