计算机网络庞大且复杂,很难一言或几言以蔽之。因此,这里我们只考虑最一般的场景,所谓“一般”,就是...比如,没有缓存,客户机和服务器不在一个局域网,输入的是一个域名而不是IP地址,etc。我们采用自顶向下的方法,也是时间顺序的方法,来解答这个问题。浏览器是C/S架构中的客户端,通过想服务器发送请求,获取文件(html,js,css等),再通过浏览器引擎的解释和渲染,将这些文件呈现成你现在看到的样子。
1、TCP/IP参考模型
首先,我们不得不了解一下TCP/IP参考模型。
如下图所示,TCP/IP参考模型分为四层:应用层、运输层、网络层和接口层。浏览器所完成的工作就属于应用层的范畴。
<img src="https://pic2.zhimg.com/50/0ff21f5171c24887eba7b2d61f33921d_hd.jpg" data-rawwidth="160" data-rawheight="257" class="content_image" width="160">
1、TCP/IP参考模型
首先,我们不得不了解一下TCP/IP参考模型。
如下图所示,TCP/IP参考模型分为四层:应用层、运输层、网络层和接口层。浏览器所完成的工作就属于应用层的范畴。
<img src="https://pic2.zhimg.com/50/0ff21f5171c24887eba7b2d61f33921d_hd.jpg" data-rawwidth="160" data-rawheight="257" class="content_image" width="160">
- 应用层: 为用户提供各种服务,比如我们浏览网页时用到的HTTP,收发邮件时用的SMTP,登录远程主机用的SSH。
- 传输层:提供端到端的传输服务。更具体地讲,提供进程到进程的传输服务。
- 网络层:和传输层一样,可以概括为提供端到端的传输服务。更具体地讲,网络层提供主机到主机的传输服务。
- 网络接口层(链路层):为直接连接的设备提供传输服务,将数据帧转换为比特流,并将比特流转换为物理电路的电压高低信号。
假设我么输入的地址是
zhihu.com
DNS具有两层含义:①一个由分层的DNS服务器实现的分布式数据库;②一个允许主机查询分布式数据库的应用层协议。有三种类型的DNS服务器:根DNS服务器、顶级DNS服务器和权威DNS服务器。这些服务器以下图的层次结构组织起来。
除此之外,还有一类重要的DNS,称为本地DNS服务器。严格来说本地DNS服务器并不属于DNS服务器的层次结构,但它在整个查询的过程中却扮演着重要的角色。
首先,浏览器所在的主机向本地DNS服务器发送一个含有知乎域名的DNS查询报文。本地DNS服务器把查询报文转发到根DNS服务器,该根DNS服务器注意到其com后缀并向本地DNS服务器返回com的顶级域名服务器的IP地址。该本地DNS服务器再次向comDNS服务器发送查询请求,comDNS服务器注意到其 http://zhihu.com后缀并用负责该域名的权威DNS服务器的IP地址作为回应。最后,本地域名服务器将含有 http://zhihu.com的IP地址的响应报文发送给客户端主机。
首先,浏览器所在的主机向本地DNS服务器发送一个含有知乎域名的DNS查询报文。本地DNS服务器把查询报文转发到根DNS服务器,该根DNS服务器注意到其com后缀并向本地DNS服务器返回com的顶级域名服务器的IP地址。该本地DNS服务器再次向comDNS服务器发送查询请求,comDNS服务器注意到其 http://zhihu.com后缀并用负责该域名的权威DNS服务器的IP地址作为回应。最后,本地域名服务器将含有 http://zhihu.com的IP地址的响应报文发送给客户端主机。
这里的查询过程是包含递归查询和迭代查询的,客户端主机发送给本地服务器的查询是递归查询,而后面的三个查询是迭代查询。最高票 @郭无心 的答案中给出的递归查询应该是迭代查询才对。
2、封装HTTP请求
其实这里主要讲HTTP报文的格式的。可以看到,这个请求里面包含了请求的方法GET,请求的路径“/”,请求的主机名,客户机的类型以及一些其他的信息。
前面辛辛苦苦通过DNS获得的IP地址怎么没有用到?HTTP请求报文里根本没有这一个字段。继续往下看。
3、建立连接
在应用层和传输层之间,更准确地讲是在浏览器进程和操作系统提供的TCP服务程序之间,有一个很重要的东西叫做套接字(Socket),如下图所示。如果把一台主机比作一座房子,把进程比作房子里面的房间,Socket相当于房间的门。不管是房间的人要出来还是外面的人要去到某一个房间,都必须先通过Socket这一道门。套接字的作用是实现传输层的多路复用和多路分解。在应用层可以同时运行多个进程,每个进程都需要通过传输层来收发分组,而传输层的TCP进程只有一个,当TCP进程收到一个分组后,该怎么确定应该转发给哪个进程呢?答案是通过套接字,这就是多路分解。同样的道理,多路复用就是进程将分组通过各自的套接字转发给传输层。TCP套接字是由一个四元组(源IP地址、源端口号、目的IP地址和目的端口号)来标识的。
2、封装HTTP请求
其实这里主要讲HTTP报文的格式的。可以看到,这个请求里面包含了请求的方法GET,请求的路径“/”,请求的主机名,客户机的类型以及一些其他的信息。
GET / HTTP/1.1
Host: zhihu.com
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64;
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
3、建立连接
在应用层和传输层之间,更准确地讲是在浏览器进程和操作系统提供的TCP服务程序之间,有一个很重要的东西叫做套接字(Socket),如下图所示。如果把一台主机比作一座房子,把进程比作房子里面的房间,Socket相当于房间的门。不管是房间的人要出来还是外面的人要去到某一个房间,都必须先通过Socket这一道门。套接字的作用是实现传输层的多路复用和多路分解。在应用层可以同时运行多个进程,每个进程都需要通过传输层来收发分组,而传输层的TCP进程只有一个,当TCP进程收到一个分组后,该怎么确定应该转发给哪个进程呢?答案是通过套接字,这就是多路分解。同样的道理,多路复用就是进程将分组通过各自的套接字转发给传输层。TCP套接字是由一个四元组(源IP地址、源端口号、目的IP地址和目的端口号)来标识的。
TCP是面向连接的,在实际发送数据之前,客户端和服务器需要建立起一个TCP连接。这种TCP“连接”只是逻辑上的链接,因为其状态完全保留在两个端系统中,中间路由器对TCP连接毫不知情。
TCP连接的建立过程如下图所示。首先,TCP先发送一个创建连接的SYN请求,告诉服务器主机“我想和你创建一条TCP连接”。当服务器主机收到SYN请求后,如果其所请求的端口号正在等待连接,则会为这一条TCP连接分配资源,并发送一个SYNACK报文段作为应答。客户主机收到SYNACK报文段后,客户机也为该连接分配资源。此时,连接已经建立起来了。客户主机还会向服务器主机发送另一个报文段,对允许连接的报文段进行确认。这就是有名的“三次握手”。
TCP连接的建立过程如下图所示。首先,TCP先发送一个创建连接的SYN请求,告诉服务器主机“我想和你创建一条TCP连接”。当服务器主机收到SYN请求后,如果其所请求的端口号正在等待连接,则会为这一条TCP连接分配资源,并发送一个SYNACK报文段作为应答。客户主机收到SYNACK报文段后,客户机也为该连接分配资源。此时,连接已经建立起来了。客户主机还会向服务器主机发送另一个报文段,对允许连接的报文段进行确认。这就是有名的“三次握手”。
可以这样简单地认为,TCP连接创建成功的标志是:客户机和服务器都创建了一个由源IP地址、源端口号、目的IP地址和目的端口号标志的Socket。
4、发送请求
请求在“三次握手”的第三次“握手”就发送出去了。
TCP报文段的格式如下图所示。
4、发送请求
请求在“三次握手”的第三次“握手”就发送出去了。
TCP报文段的格式如下图所示。
目的端口和源端口号是为了在多路复用和多路分解时选择套接字时使用的。
数据序号和确认序号是为了传输数据的完整性和顺序而设置的。
用户数据这一个字段就存储了应用层生成的HTTP报文。
ACK、SYN和FIN是在建立连接和关闭连接时使用。
其他用于流量控制、拥塞管理等用途的字符就不展开了。
5、路由寻址
现在两个端系统已经建立起了连接,请求也被传送到客户端主机的网络层。网络层是协议栈中最复杂的层次,应用层和传输层只运行在两个端系统,而网络层不仅运行在端系统,还运行在各个中间节点上。
我们先来看看IP数据报的格式。
数据序号和确认序号是为了传输数据的完整性和顺序而设置的。
用户数据这一个字段就存储了应用层生成的HTTP报文。
ACK、SYN和FIN是在建立连接和关闭连接时使用。
其他用于流量控制、拥塞管理等用途的字符就不展开了。
5、路由寻址
现在两个端系统已经建立起了连接,请求也被传送到客户端主机的网络层。网络层是协议栈中最复杂的层次,应用层和传输层只运行在两个端系统,而网络层不仅运行在端系统,还运行在各个中间节点上。
我们先来看看IP数据报的格式。
网络层实现的最重要的功能是路由选择,简单地说,就是怎么把这一个IP数据报从客户端主机出发,通过网络中的若干个路由器,到达目的主机。从概念上讲,IP路由选择是简单的,特别对于主机来说,如果目的主机和源主机直接相连(如点对点链路),或都在一个共享网络上(以太网或令牌环网),那么IP数据报就直接送到目的主机上。否则,主机把数据报发送到一默认的路由器上,由路由器来转发该数据报。大多数的主机都采用这种简单机制。
我们把网络环境简化如下图:只包含源主机H1、目的主机H2和两个路由器R1、R2。
我们把网络环境简化如下图:只包含源主机H1、目的主机H2和两个路由器R1、R2。
IP路由选择是逐跳(hop-to-hop)进行的。IP并不知道从H1到H2的完整路径。所有的IP选择只为数据报提供下一站的IP地址。路由选择机制的基础是在每一台主机和路由器里都存储着一张路由表。路由表的每一项包含了目的主机IP地址、下一跳路由器(或主机)的IP地址、相对应的网络接口以及其他必要的信息。当一个数据报到达一个节点时,IP路由选择完成以下工作:
在我们的例子中,H1通过搜索自己的路由表将数据报转发给R1,R1根据路由表转发给R2,最后到达H2。
6、关闭连接
目标主机收到了请求后,自底向上地对该请求进行处理。链路层把数据报传给网络层,网路层将TCP数据段通过对应的Socket传给应用程序。应用程序处理请求后产生一个应答的HTTP报文,又经过了一层层的封装、一跳跳的传输到达了源主机。
这样就结束了吗?那一条TCP连接还没有关闭呢,源主机和目标主机上都为它分配了资源呢,如果不释放掉的话资源很快就会耗尽(DDoS攻击就是利用这一点)。于是,当传输层收到了应答之后,就要关闭这条连接了。但是,又不能悄悄地自己关了,目标主机那边还不知道你要不要关闭呢。于是乎,就有了对应创建TCP连接“三次握手”的关闭TCP连接“四次挥手”。
如下图所示,客户端向服务器发出了FIN报文段,服务器收到后,回复一个ACK应答。然后,服务器也向客户端发送一个FIN报文段,随后关闭了服务器端的连接,释放了资源。当客户端收到之后,又向服务器回复一个ACK应答。过了一段计时等待,客户端也关闭了连接,释放资源。这一段计时等待的时间是为了客户端重传最后的ACK防止其丢失。
- 搜索路由表,寻找能与目的主机IP地址完全匹配的表目。如果找到,则把报文发送给下一跳节点。
- 搜索路由表,寻找能与目标网络号相匹配的表目。如果找到,则把报文发送给下一跳节点。
- 搜索路由表,寻找“默认”的表目。如果找到,则把报文发送给下一跳节点。
在我们的例子中,H1通过搜索自己的路由表将数据报转发给R1,R1根据路由表转发给R2,最后到达H2。
6、关闭连接
目标主机收到了请求后,自底向上地对该请求进行处理。链路层把数据报传给网络层,网路层将TCP数据段通过对应的Socket传给应用程序。应用程序处理请求后产生一个应答的HTTP报文,又经过了一层层的封装、一跳跳的传输到达了源主机。
这样就结束了吗?那一条TCP连接还没有关闭呢,源主机和目标主机上都为它分配了资源呢,如果不释放掉的话资源很快就会耗尽(DDoS攻击就是利用这一点)。于是,当传输层收到了应答之后,就要关闭这条连接了。但是,又不能悄悄地自己关了,目标主机那边还不知道你要不要关闭呢。于是乎,就有了对应创建TCP连接“三次握手”的关闭TCP连接“四次挥手”。
如下图所示,客户端向服务器发出了FIN报文段,服务器收到后,回复一个ACK应答。然后,服务器也向客户端发送一个FIN报文段,随后关闭了服务器端的连接,释放了资源。当客户端收到之后,又向服务器回复一个ACK应答。过了一段计时等待,客户端也关闭了连接,释放资源。这一段计时等待的时间是为了客户端重传最后的ACK防止其丢失。
剩下的事情就交给浏览器了
作者:何伟鹏
链接:https://www.zhihu.com/question/34873227/answer/70038032
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
链接:https://www.zhihu.com/question/34873227/answer/70038032
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。