大话 TCP/IP

前言

一切还要从那个经典问题出发:html

当你在浏览器中输入 www.google.com/ 而且按下回车以后发生了什么?前端

Whaaat!!! 都 9012 年了你还在问这个问题!git

解析 URL,DNS 查询,得到服务器 IP 地址,向目标地址发送 HTTP 请求,服务器收到,响应,返回页面,浏览器接收,渲染,bingo!github

你露出满意笑容,又是一个满分回答。浏览器

停!还没完呢。请问这位同窗,你发送的请求是怎么到达目标服务器的,服务器的响应又是如何回来的?缓存

你陷入沉默,说了一些 TCP 协议、OSI 模型、路由器之类的词。服务器

此时问题又来了:浏览器又是如何将请求发送出去的?网络

空气中的沉默加深了几分,仿佛要滴出水来······app

这篇文章,我将以网络通讯经常使用的 TCP/IP 模型为主,解释网络通讯涉及的各个阶段,无论是常规的页面访问,仍是咱们业务中常见的 HTTP 请求,都包含在这样的过程当中,了解总体对前端开发者们颇有益处。开始吧!socket

目录

  1. TCP/IP 参考模型是什么
  2. 一次完整的网络通讯过程
  3. 各个阶段的深刻理解

1、TCP/IP参考模型是什么

在进入具体的解释以前,咱们对 TCP/IP 协议的前世今身作一个简单回顾。

所谓无规矩不成方圆,网络诞生之初,为了保证网络通讯的有序进行,相关组织开始着手制定各类通讯协议,例如最先的网络控制协议(NCP),到后来耳熟能详的 OSI 七层协议等,整个因特网在这些协议的制约下迅速发展。事物老是发展变化的,技术天然更新换代。到上一世纪 80 年代,美国国防部的 ARPA 网(也就是阿帕网,互联网的鼻祖)项目中,TCP、IP 协议最先被提出来获得应用,而且因为其优异性迅速成为互联网通讯的主流通用协议。

这一协议最先得名是由于两个最重要最早被提出的协议 TCP 和 IP,后来,互联网通讯的各种协议(HTTP、IP、DNS、TCP、ARP)总体都被归入这一协议体系中,被统称为“TCP/IP 协议族”。

也就是说,TCP/IP 协议族最先的确只有 TCP 和 IP 两个协议,如今则是一系列与网络通讯有关的各种协议的集合。对应这一协议族,同时发展出了TCP/IP 参考模型,这一模型是一个抽象出来的分层模型,TCP/IP 协议族中的全部协议被归类到这一模型的 4 个层次中,每一层相互独立,下一层为上一层提供服务,各个层次间互相协做,完成了互联网通讯的主要工做。

这四个层分别是:网络访问层(又叫数据链路层或者网络接口层)网络层传输层应用层,你们一般将这四个层次与更为详细的OSI七层模型映射:

在 TCP/IP 参考模型中,各项通讯协议各有归属,例如咱们在浏览器中经常使用的:HTTP(超文本传输协议)、DNS(域名系统)、FTP(文件传输协议)、SMTP(简单邮件传输协议等)都是属于应用层协议,而 TCP、UDP 则属于传输层协议,IP 则属于网络层协议。更多的通讯协议,你们能够搜索了解。咱们这篇文章主要分析以 HTTP 为主的通讯过程。

(常见协议)

2、一次完整的网络通讯过程

为了对 HTTP 请求的通讯过程有一个更好的理解,我将从 TCP/IP 四个层次出发,对应各个层次的通讯实体,或者媒介(例如浏览器,路由器以及网线等),看各个协议是如何在这些通讯实体中发生做用,将一个请求发送到服务器,服务器的响应又是如何赶回来的。

总体来说,一次完整的通讯,很像快递邮递包裹,物品被加上包装,写上地址信息和联系方式,通过一个又一个的快递中转站,到达收货人的位置,在网络请求中,请求的数据就是须要快递的物品,IP 地址和 MAC 地址就是通讯的地址,网线和路由器、交换机和集线器等就是运输道路和快递中转站,网络协议则能够看作快递员和快递政策,而和快递相似的是,网络通讯也会出现丢包(包裹损坏)等状况。因此说,一个简单的 HTTP 请求,要完整地拿到请求信息,中间有若干操做系统组件、通讯协议、通讯实体参与,才能保证通讯的顺利进行。

那么,这个快递过程,具体是怎么进行的呢?

其基本原则是,经过分层的顺序,发送端由上往下发送,接收端则由下向上接收。为了保证数据顺利发送到下一个层次,会在发送在其头部加上一些必要的信息,这些信息是为了保证数据的完整和符合需求的约束信息。发送 HTTP 请求时,常常会设置 Request Header,例如 Content-Type:text/html 是向服务器说明,我须要的是 HTML 页面,你返回其余东西是不行滴。

这些头部信息还可能包含协议信息,请求路径、请求方法等,但这仅仅是发生在应用层,整个通讯过程,通过四个层次,会被依次加上 HTTP 请求头,TCP 头部、IP 头部以及以太网头部。数据加上这些头部信息以后,才会被发往下一层,数据通过重重包装,从你的网卡出发,穿过若干路由器,网线,交换机,到达目标服务器所在的子网,服务器要作的则是相反的过程,它会根据前面加上的头部信息,层层解析,最后到达服务器被处理(处理就是服务端程序代码的责任),以后再将响应数据返回。总体过程以下图:

(图片来自谢希仁版《计算机网络》)

数据在各个层次间依次传递,其传递的数据单位咱们能够统一理解为数据包,数据包在不一样的层次有不一样的称呼,咱们熟悉的是,其从应用层出发时,将之称为 HTTP 请求消息(message)或者报文,为其加上消息头以后,发送至传输层,加上 TCP 头部,叫它报文段(segment),到网络层,加上 IP 头部,成为 IP 数据,到了最后的网络访问层,其已经套上层层包装,在这里在为其加上以太网首部的同时,还会加上一些尾部信息,摇身变为帧(framing),这个过程叫作封装过程。无论怎么叫,数据在各个层次间,是以数据包的形式传递,当数据量大时,还会出现分包传递的状况。

接下来我将这个过程进行扩展,看看在输入 www.google.com/ 以后,TCP/IP 的各个层次间,前面提到的通讯协议是如何参与其中的:

3、各阶段发生了什么

1. DNS 查询

URL 只是为了人类更友好识别网络程序而设置的互联网资源的定位标识,浏览器首先会对 URL 进行解析,获取到请求的协议(https),域名(google.com),路径(/),因为没有其余子域名,也就是查询 google 的默认主页。解析完毕后,DNS 出场。

DNS,也就是域名查询系统,负责 URL 对应的 IP 地址的查询,每一个操做系统会内置 Socket 协议库,协议库中有解析器(resolver)专门负责这个过程,又是一个漫长的过程(固然咱们等的时间不会很长),这里再也不具体展开,感兴趣的同窗能够看看我在文尾列出的参考资源 How DNS works,其用生动有趣的动画形式展现了这一过程,十分有趣。

通过 DNS 查询,浏览器拿到了请求资源的 IP 地址。IP 地址,又叫网际协议地址,是分配给网络上设备的数字标识,也就是说,只要联网的设备,例如咱们的电脑手机以及路由器等都是有 IP 地址的。其是咱们的请求数据识别服务器在网络中的位置的必须标识。

2. Mac 地址查询

IP 地址在网络层使用,但在实际的数据链路上传递数据时,在同一个链路中不一样的计算机,其必需要使用另外一个地址来识别—— Mac 地址,又叫作物理地址。

说到这里,岔开一句,在网络通讯中,咱们一般提到三个地址:IP 地址、Mac 地址以及端口号,三者分别表明的是:

IP地址:网络中互联的主机和路由器的标识。 Mac 地址:每一个网卡硬件的物理地址。 端口号:识别同一个主机上不一样的应用程序,也能够理解为程序地址。

因此,在一个网络通讯中,咱们须要用到五大识别符:源IP地址、目标IP地址、协议、源端口号和目标端口号。

言归正传,Mac 地址是每个网卡被生产的时候就写死在其中的,因此其是不变且惟一的,那么如何获得服务器的 Mac 地址呢,又一个协议闪亮登场——ARP。

ARP,英文全称叫作 Address Resolution Protocol,也就是地址解析协议,其做用是,根据IP地址获取通讯设备的物理地址,其工做原理相似于之前咱们常见的广播,它会将包发送给同一以太网的全部主机,若目标主机的 Mac 地址与对应的 IP 地址命中,则找到了目标,可是,若每次查询都要给全部的主机发送 ARP 请求,网络中则会出现不少 ARP 包,所以,每一个主机都会有一个 ARP 缓存,里面存放着经常使用的 MAC 地址,主机会优先从缓存中查询是否有须要的信息,若是有,就再也不发送广播。Mac 地址会在网络层加入 IP 头部发往网络访问层,其实你会发现,为了提升效率和性能,网络通讯中随处可见缓存,HTTP 缓存、DNS 缓存以及 ARP 缓存等。值得了解的是,在IPv6中,有一个 NDP(邻居发现协议)替代 ARP 来完成这个工做。

3. 数据传输——套接字来帮忙

咱们前面提到操做系统中有一个协议库,负责本机中网络通讯的不少功能,在 DNS 查询的时候,协议栈中的解析器就参与其中,当应用层获取到服务器的 IP 地址和 Mac 地址,已经拥有了数据传递的必要条件,接下来,浏览器会向操做系统的协议库发出委托指令,调用其中 Socket 库中的程序组件,创建套接字(socket),套接字的本质能够理解为一个数据通道的出入口,其执行的是一个“打开,读/写,关闭”的流程。

在进行数据传输时,客户端和服务器都会建立一个套接字,以后调用 socket 库中的 connect 组件,该组件会依据描述符(套接字的匹配令符,与服务端的套接字的接头暗号),服务器的 IP 地址和端口号,在浏览器和目标服务器之间创建一个传输通道(实际上并无真实的通道,中间隔着N多网关、路由器和防火墙,这样说更好理解),而大名鼎鼎的 TCP 三次握手实际就是发生在这个阶段,咱们会在后面具体介绍 TCP 到底作了什么。

通道创建以后,接下来就是数据的读写操做,咱们的程序代码没法直接控制套接字,它依然会委托 Socket 库中的组件来完成数据的读写(write 和 read),数据传输完成后,服务器会主动执行断开操做,调用 Socket 库中的 close 组件断开链接,浏览器发现以后,也会执行断开操做,数据传输完成。

能够看到,在应用程序代码的背后,操做系统中内置的组件库和互联网协议互为网络通讯的左膀右臂,共同负责整个通讯过程,缺一不可。

4. 三次握手

TCP 和 UDP 是传输层中的两个主要协议,二者的区别是:前者是面向链接的(实际就是套接字管道)、可靠的流协议,后者则并不可靠,它采起一种“尽最大努力”的传输策略,你们能够记住,浏览器、邮件等应用程序通常使用 TCP 传递数据,而像 DNS 查询等较短的收发则使用 UDP。咱们主要介绍 TCP。

总体来说,之因此要在发送数据以前创建套接字,正是由于 TCP 是面向链接的传输协议,在传输协议面前,你发送的内容可有可无,它们会将之看为一串具备必定长度的数据。

为了保证数据传输的可靠,TCP 在套接字创建链接时,采用“三次握手”策略传输数据。

下面是一张三次握手流程图:

图中的 syn 是 Synchronize Sequence Numbers 的简写,也就是同步序列编号,拥有数据传输序列的标识。

ack 指的是acknowledgement,表示确认。

通俗来说,是这样一个过程:

第一次握手:客户端尝试链接服务器,向服务器发送syn包(同步序列编号),syn=j,其进入SYN_SEND 状态等待服务器确认:我已准备好,随时出发!

第二次握手:服务器接收客户端 syn 包并确认(ack=j+1),同时向客户端发送一个 syn 包(syn=k),也即 syn + ack 包,此时服务器进入SYN_RECV 状态:收到请求,随时接收。

第三次握手:客户端收到服务器的 syn + ack 包,向服务器发送确认包 ack(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED 状态,完成三次握手:OK,我知道了,那咱们开始发送数据。

你可能会以为至关麻烦,确认一次就能够了嘛,收到了吗?收到,传输,为何须要三次握手呢?

其实,为了保证数据传输的绝对可靠,三次确认是最少的次数,试想这样一种状况:在第一次获得确认后,客户端发送数据出去,可是这个数据因为中途网络等问题,迟迟到不了服务端,服务端选择关掉通道,但通道关闭后,刚刚的数据又跑过来了,这时候,服务端会将这个数据视为来自客户端的新的传输请求,赞成创建链接,而创建一个新的链接,可是,客户端并无发送数据,因此,它会忽视服务端的确认,也不会回应给服务端,服务端就在傻傻滴等待,但这种等待是没有结果的,这就形成了服务端资源的浪费。

我在知乎上看到另一种理解:之因此须要三次握手,本质的缘由是,传输信道是不可靠的,你不知道网络会在何时出什么样的问题,因此,为了保证传输的确可靠,三次握手是理论上的最小值。

TCP 传输数据时,并非将全部数据一股脑全丢出去,而是会将数据存放在一个的发送缓冲区,而且会等待应用程序的下一段程序到达,之因此这样干,是由于一收到数据立马发送,极可能会形成信道的浪费与闲置,致使网络效率过低,就像明明很宽的马路,非要像过独木桥同样经过。

而 TCP 如何决定数据何时会发送,其拥有一套计算机制,总体来讲,是按网络包的长度以及应用程序送包过来的时间,虽然你的数据很小,但你半天不发送,我也不会一直傻等着。

还有一种状况是,当发送过来的数据包很大时,会在缓冲区对包进行拆分发送,拆分的时候,TCP 模块会计算好每一块数据的开头和结尾的字节数,并将之写在 TCP 头部信息中,以待对方确认,根据这些起始序号,接收方能够判断是否有数据遗漏的状况。

每发送一个包,就须要等待 ack 包的确认,这也是一种资源浪费,因此为了利用等待 ack 的空闲时间,数据能够不用等待 ack 直接发送,可是,这会出现一种状况,一边一味地发送,但超过了接收方的处理能力,就会出现网络拥堵,得不偿失。为了解决这个问题,TCP 采起了一种滑动窗口的发送策略,它的原理是这样的:

滑动窗口其实是数据流量控制策略,咱们能够将全部的数据想象为一个序列,而窗口则是数据可处理的数据大小,接收方会将窗口的大小写入 ack 包的头部信息中,告知发送方,发送方会据此动态调整发送的速率,因为传输的持续进行,这个窗口大小会动态变化,所以达到了流量的控制,其本质的目的是,不要发的太快,让接收方处理不过来。

(滑动窗口示意图)

接下来的路

上面咱们只提到发送和接收,可是在浏览器和服务器之间,可能隔着极多的网关、路由器、交换机等,数据是如何在庞大无比的因特网上找到服务器的呢?

这就是网络层协议的用武之地了。

实际上,这一切在请求发送以前已经准备好了,咱们使用 DNS 和 ARP 等方式,获取到了目标服务器的 IP 地址和 Mac 地址,这两个地址引导发送的数据包到达服务器,IP 地址用于在网络中的全部主机中匹配通讯的目标主机,IP 地址包含网络标识主机标识,前者用于区别不一样的网段,后者找到同一网段的不一样主机,数据到达路由器时,路由器会根据网络标识将数据转发到相应的网段,到达相应的网段以后,又会根据主机号,到达真正的主机。

说到这里,你们可能会有一个疑惑,既然 IP 地址都能找到目标服务器,为何还须要 Mac 地址

请容我解释:

在同一个网段内通讯时,只用知道 Mac 地址,就能够精准找到目标,可是,互联网上的网络数量无比庞大,网络被各大运营商分割为多个网段,每一个网段又有多个子网,若是仅仅知道一个 Mac 地址,要在全部的网络设备进行匹配,就是至关大的工程了,这时候,IP 地址的妙用体现出来了:它能够用来找路,这就相似于快递中的省市地区等,而 Mac 地址多是惟一的名字,你在全中国找一个小强的人那就太多了,可是你要具体到某一个村或小区,就很简单了。

另一个缘由是,交换机这个东西,只认 Mac 地址,就如同路由器根据 IP 地址决定网络请求的转发路线,交换机经过 Mac 地址来肯定具体的网卡位置。

路由器、交换机、网线、光纤等正是 TCP/IP 四层协议的最底层,网络访问层,也就是 OSI 模型中的数据链路层和物理层,在这一层,数据被加上以太网首部,封装成帧,在各个路由器之间转发传送,常常来讲,路由器之间的传送又有经常使用的点对点协议,也就是PPP(Point-To-Point Protocol),这是一个网络访问层协议,PPP会在帧的先后加上帧界定符进行发送。最后,到达服务器所在子网,会将消息转交网络层向上传递。

向上传递的过程如前所述,乃是解析头部信息,最终到达服务器的相反过程,再也不细述。

这个过程咱们能够在前面的总体过程图清晰看到,请求数据到达服务器所在子网的路由器以后,又是一个由下而上的过程,这与客户端发送数据基本相反,每通过一个层次,都会解析前面添加到请求数据上的多层头部信息,交由上一层处理,在整个 TCP/IP 协议栈的帮助下,咱们的请求数据终于到达了目标服务器,穿过服务器的网卡,服务器操做系统一样有协议栈来负责找到服务端程序对应的端口,将数据交由服务端应用程序处理。

服务器会根据咱们的请求头信息,处理返回结果,以后,请求响应信息从新出发,再次回到浏览器。

浏览器收到请求后,通过解析、渲染过程,页面呈如今咱们面前。

参考连接

  1. How DNS works
  2. 谢希仁《计算机网络》
  3. 户根勤《网络是怎样链接的》
  4. what-happens-when...
  5. 通俗大白话来理解TCP协议的三次握手和四次分手
相关文章
相关标签/搜索