前端都应该懂的 TCP/IP 知识

1,509 阅读10分钟
在大部分前端的日常工作中,都不需要和 TCP/IP 打交道,所以很多前端同学对于 TCP/IP 都不太了解,甚至会说出类似“HTTP的3次握手”这样的错误描述。
不懂 TCP/IP,你可能照样能把页面切出来,但是很可能会把 TCP/IP 相关的优化给忽略了。做出来一个页面不难,做“好”一个页面才是对前端的挑战,大公司对前端的要求也绝不仅仅是把页面做出来就行了,了解 TCP/IP 相关的前端优化手段,已经是一个大公司对前端开发的一个基本素质要求。
事实上最近我在阿里当前端面试官的时候,也会关注候选人是否了解 TCP/IP 相关的知识,如果没有,我会认为Ta是那种网络知识薄弱,守着 HTML、CSS、JS 一亩三分地,不愿意拓展技术视野的人。一般这种人面试很容易被挂掉的。
所以在这里和大家分享一下,前端都应该懂的那些 TCP/IP 知识。

一、五层网络分层模型

因特网,也就是我们说的互联网,按照因特网协议簇可以抽象成下图示的五层。另外还有 OSI 七层模型,不过不常用,我们先不关注。
常见的五层分层模型:
  1. 物理层:顾名思义,电脑的网卡插口、网线等相关的硬件构成了最底层的物理层。
  2. 数据链路层:在物理层的基础上,用以太网之类的协议传输数据。如果你的设备只在局域网里运行,到这一层可能就够用了。如果需要联上互联网,至少得去到第三层。
  3. 网络层:Internet Protocol(因特网协议)简称 IP,这一层有多重要,从“因特网”这个广为流传的词就可以知道了。简单来说,网络层为互联网上的两台电脑,提供了不可靠的数据传输服务。
  4. 传输层:Transmission Control Protocol(传输控制协议)简称 TCP,可以说是互联网上应用最广的协议了,简单来说,TCP 是在第三层 IP 层的基础上,提供了可靠的数据传输服务。这一层比较常见的还有 UDP 协议,相对没那么广泛应用。
  5. 应用层:在 TCP 上的应用层协议非常多,最常见的跟前端关联最紧密的,当属 HTTP 层了,另外还有像传输文件的 FTP 协议、控制邮件发送的 SMTP 协议。HTTP 协议笔者后面会有专门的文章讲,这里先略过。
其中最关键的就是 TCP 层和 IP 层,所以我们一般将这个网络分层模型简称为 TCP/IP。

二、IP 协议

在几十年前,每个大学或者机构自身会有一个局域网,没有所谓的互联网。为了让不同局域网的计算机能连接起来,IP 协议出现了。它定义了每个在互联网上的设备都有一个 IP 地址,这个 IP 地址是由 32 位,也就是 4 个字节组成的。最常见的地址表达形式是,每个字节用十进制表示,例如 00000010 => 2,11000000 => 192,然后每个字节用"."分开,所以我们看到的 IP 地址都是用形如 192.168.0.1 的形式来表示的。
当设备联上互联网分配到一个 IP 地址后,就可以愉快地给网络上的其它机器发数据了,比如给QQ的服务器发消息,或者给网易的服务器发邮件。在 IP 层,数据是按 Packet (报文)为单位传输的,报文在路由器、交换机的帮助下,在各个大小网络之间穿梭,最终到达目标地址。 IP Packet大概长这样:
IP Packet 构成 - 图片来自维基百科
正如大部分的网络协议一般,IP Packet 可以看作两大部分,一部分是图里的 Data,是我们实际要传输的数据,比如说一张图片。Data 以外的可以笼统地称为 Header,Header 包含了很多信息,例如第一个字节 Version 表示协议的版本,Source addressDestination address 表示这个 IP 从哪来(来源 IP 地址),要到哪去(目标 IP 地址)。前端同学没有必要对全部字段的含义了解得一清二楚, 需要关注的点是在 IP 层我们抽象出了 IP 地址。
另外 IP 协议有几个值得注意的特点:
  1. 只作“尽最大努力的交付”,就是说我们发出去的 IP 报文可能在某个中转路由器丢了
  2. IP 报文的到达是不能保证顺序的,可能我发过去的顺序是报文1、报文2,但是对方接收到的顺序是报文2、报文1
  3. IP 协议是无连接的,在发送数据前,不需要先打招呼,直接丢过去就是了
可以看到这几个特点对于应用开发者来说是非常不方便的,所以人们在 IP 层上定义了一个新的协议,用来解决这些问题,这个协议就是接下来要说的 TCP 协议。
NOTE: 上文是基于应用最广泛的 IPv4 描述的,关于 IPv6,目前在国内还没得到大范围推广,这里不展开描述,前端同学只需要记住 IPv6 是 IPv4 的进化版,解决了 IPv4 的几个痛点问题,比如地址空间不够用了,传输效率不高等。后续有机会咱们再写篇《前端应该懂的 IPv6 》。

三、TCP 协议

Transmission Control Protocol(TCP) 意为“传输控制协议”,它是在 IP 层上抽象出来的协议,它存在的主要意义就是为了解决 IP 协议传输数据带来的几个痛点,所以 TCP 有以下几个特征:

1. TCP 提供可靠的、有序的传输机制

这是 TCP 最重要的一个功能点,开发者在开发应用时,如果需要连接网络上的另一台设备发送数据,只需要调用系统提供的 TCP 相关 API (例如 Node.js 里面的 net 模块),就可以和目标设备连接连接并发送数据,应用开发者不需要关心怎么处理 IP 报文可能会丢失的问题,也不用自行对无序到达的IP报文进行重新排序组装,因为 TCP 协议已经通过包括“超时重传”和“重复累计确认”等机制帮你处理好了。
值得一提的是,在浏览器上没有类似 Node.js 的 net 模块那么底层的 TCP 操作 API,不过 WebSocket 协议在 TCP 协议之上,倒是提供了相对 HTTP 协议要更接近 TCP 底层 API 的功能。

2. TCP 是面向连接的

客户端想要发送数据给服务端,在发送实际的数据之前,需要先在两端之间建立连接,数据发完以后也需要将该连接关闭。建立连接的过程就是我们常说的 TCP 三次握手:
图为 TCP 的三次握手
如上图示,建立 TCP 连接需要这三个步骤:
  1. 客户端发送一个 SYN 告诉服务端它想建议一个连接,SYN 代表 Sychronize,意为同步
  2. 服务端收到 SYN 后,返回一个 SYN-ACK,ACK 代表 Acknowledge,意为确认
  3. 客户端最后发送一个 ACK,服务端收到时,标识着三次握手的完成,这之后就可以愉快地传输数据了
由此可见,三次握手的时间消耗为至少一个 RTT(Round Trip Time),即网路上至少一个来回,大部分时候这意味着几百毫秒的时间,如果服务器在国外或者客户端网络不好,RTT 超过一秒也完全是有可能的。
这也解释了为什么我们在谈前端优化的时候,经常提到要减少建立 TCP 连接,就是因为三次握手的时间消耗会带来性能损失。像精灵图这种合并图片以减少 HTTP 请求的技术,本质上是为了减少建立多个 TCP 连接带来的性能损耗,在 HTTP 早期版本还是非常有用的。而在 HTTP/2 里,由于对单个 TCP 连接的多路复用,无需建立多个 TCP 连接,所以精灵图这种优化手段已经不必要了,HTTP/2 对于前端也是一个颇为重要的知识点,后面会另起一篇文章讨论。

3. TCP 抽象了端口(ports)的概念

IP 协议抽象了 IP 地址的概念,可以将数据发送到指定的主机,但是一台主机上运行着多个程序,哪个报文应该交给哪个程序阅读,是一个问题。所以 TCP 和 UDP 都在传输层这一层抽象出了 ports 端口的概念。
例如我们平时说的 HTTP 80 端口,或者 HTTPS 443 端口,其实就是 HTTP/S 服务器监听这两个约定的端口;浏览器向服务器发出 HTTP/S 请求时,如果 URL 没有指定端口,例如 http://127.0.0.1,浏览器就会根据协议找到对应的默认端口,例如 HTTP 对应 80,去建立 TCP 连接。
值得一提的是,占用 0-1023 这些端口一般需要 root 权限,因为这些端口一般用来提供常见的 网络服务。黑客在攻击一个服务器时,一般也会进行端口扫描,看看这个服务器都提供了什么服务,然后再对这些服务有针对性地尝试相应的攻击手段。
图为 TCP 分段
IP 传输的一个数组包称为 Packet(报文),为了区别开来,TCP 传输的一个数组包则被称为 Segment(分段)。从上面 TCP segment header 的组成可以看到有 Source Port Destination Port 分别表示来源端口和目标端口,这就是 TCP 抽象出来的 ports 端口,一般也称为 Socket(套接字),每个设备上最多可以有 2^16 = 65536 个端口,端口编号范围为 0 - 65535。
一个端口对应一个 TCP 连接,因此一个应用程序建立了一个 TCP 连接就会占用系统的一个端口,可见端口和内存、CPU一样都是有限的系统公共资源,需要谨慎地有效地利用。这也解释了为什么浏览器对于一个页面上,针对某个域名最多只允许同时建立6条连接(不同的浏览器,这个数字可能不一样,但差不了多少),如果在某个域名下有非常多的资源需要同时请求,只能老老实实排队等待。
这个限制也催生了一种新的前端优化手段,就是将资源放不到不同的域名下以突破浏览器的针对单个域名的并发连接限制,例如把图片和 API 用不同域名的服务器来伺服。
当然了如果用到 HTTP/2,针对一个域名只需要一条 TCP 连接就够了,也就不需要担心浏览器的并发限制了。

四、结语

本文简单探讨了 TCP/IP 里一些值得前端了解的知识点,但这仅是 TCP/IP 的冰山一角,还有很多像 IP 寻址方法、TCP 的拥堵控制算法等等的技术细节也是挺值得开发者去了解的。想要学习更多 TCP/IP 细节的同学可以了解一下《TCP/IP详解卷1》,维基百科上也有非常全面的描述。
前端同学学习了 TCP/IP 知识,并不会加快你切图的速度,但是了解这些技术原理,可以加深你对一些前端性能优化手段的理解,做到真正的“知其然,知其所以然”。
如果本文对你有所帮助,欢迎点赞、关注,你的支持就是作者创作的动力 :-)