网络基础 - TCP/IP协议
# 网络基础 - TCP/IP协议
之前经常看到一道面试题————浏览器从输入URL到页面渲染的过程中发生了什么?
其实看到题目一瞬间,脑海能想到一个大致过程,但过程中的细节就不太清楚了。
这个过程可以被分成两个部分,网络通信和页面渲染,前端相对于后端而言,在网络通信这块的熟悉度可能没有那么高,所以来认真看一看。
# 网络分层
首先一个问题,为什么要进行网络分层?
我现在的答案是,将一个复杂的通信过程简单化,让每一层专注于做本层的事情,再相互配合最终实现通信。
第二个问题,既然是网络分层,那应当如何分层?
目前的网络层次可划分为 TCP/IP 四层模型 和 OSI 七层模型,其中相对于TCP/IP 四层模型还有五层模型,但他们都是以OSI 七层模型优化来的,OSI 七层模型太过细化,相对应的TCP/IP 模型更具有实际应用价值。
模型概览:
# TCP/IP 五层模型
以五层模型来了解一遍,其中物理层和数据链路层偏向硬件,但也稍作了解一番。
# 物理层
为数据端设备提供传送数据通路、传输数据,其中的数据是以比特的形式传递的。
# 数据链路层
定义数据的基本格式,如何传输,如何标识。
在链路层中,通过以太网协议的规定,将比特流组合成字节形成一组由电信号构成的数据包(这种数据包我们称之为帧,每一个帧由 标头 和 数据 两部分组成)。
对数据进行处理封装成数据帧并传递和错误检测的层就是数据链路层。
# 帧(frame)
帧是数据链路层的传输单元,由数据链路层首部(即标头)和它携带的的分组(即数据)组成。根据协议的不同,有以太网帧,PPP帧等。
以太网帧结构
- 一个帧以7个字节的前导码和1个字节的帧开始符作为帧的开始
- 标头包含源和目标的Mac地址以及表明上一层网络协议的类型
- 接下来是数据
- 后面是帧验证序列,以验证帧是否损坏
- 最后有一个帧间距,两个帧发送间要再发送至少12字节的空闲线路状态码
# MAC地址
上面的图中出现了MAC地址的概念,其实进入网络的每一台计算机,都会有网卡接口,每一个网卡都会有一个唯一的地址,就是所谓的 MAC地址 ,它就是网络中每台计算机设备的唯一标识,是一串由48个字节组成的十六进制数,每台计算机在厂商生产出来的时候就标识好了,所以我们用 MAC地址 来标识是哪台机器发送的数据
# 交换机
交换机是用来处理帧,通过帧中的MAC地址来确定帧发送到哪个出口,然后会生成一张 Mac 表。其交换机的工作原理为:
交换机4个端口连接着终端,A 终端与端口1连接,发送 帧 后交换机得知端口1和 A 终端的关系,然后转发到其他三端,转发完成后得知端口2与主机 B 相对应,记录到表中。以后主机 A 与主机 B 的通信就通过端口1和端口2进行。
# 广播
在同一子网络,就是我们常说的局域网中,计算机通过广播来通信,即向同子网中全部计算机发送数据包,其它计算机根据数据包中接收者的 MAC地址 来判断是否接收数据包(计算机通过比对数据包中接收者的MAC地址与自身的MAC地址,相同则接收该数据包,不同则丢失改数据包-丢包),这种方式我们称之为广播。
# 网络层
网络层是建立主机与主机之间的通信。我们日常所接触到的网络,是由无数个子网络(局域网)构成的,广播的时候,也只有同一个子网里的计算机能够收到。如果不在一个子网下,计算机便不能通过广播的方式传送数据。此时计算机会把数据发给网关,让网关进行转发。
那么问题又来了,如何判断两台计算机是否在同一个子网下呢? 这就是网络层要干的事情,由此IP协议出现了。
# IP协议
IP协议所定义的地址,就是我们常说的IP地址 ,IP协议有两个版本,ipv4 / ipv6,ipv4地址是由32位的二进制数组成,我们一般把它分成4段的十进制表示,地址范围在 0.0.0.0 ~ 255.255.255.255,这也是我们日常最常见的ip地址。
每一台联网的计算机都会有一个IP地址,它分为两个部分,前一部分代表网络,后面部分代表主机,但这两部分所占据的二进制位数是不固定的。如果两台计算机的网络部分一致,则表示它们属于同一子网下。
例如192.168.1.101和192.168.1.102,如果它们的的网络部分都是24位的二进制,而主机部分为8位,则它们的网络部分为192.168.1,属于同一子网下。但我们现实情况是除非断网情况下能相互ping通,光看ip地址根本不知道他们的网络和主机部分各站几位,是不是属于同一子网。
为了解决这个问题,子网掩码的概念出现了
# 子网掩码
子网掩码和IP地址一样也是32位二进制数,但是它的网络部分规定全部为1,主机部分规定全部为0。
假设上面两个ip地址的子网掩码是11111111.11111111.11111111.00000000即255.255.255.0,此时我们可以将子网掩码和ip地址进行一次and运算,如果他们结果相同则表示在同一个子网下,不同则不在一个子网下。
# 路由控制
仅有 IP 地址还不足以将数据包发送到对端,还需指明路由器或主机。保存这种信息的就是路由控制表。
路由控制表中记录着地址与下一步要发送至路由器的地址。在发送 IP 包时,先确定 IP 包首部目标地址,然后在表中找到与该地址具有相同网络地址的记录,根据记录将 IP 包转发给相应的下一个路由器。
这里出现的路由器,其实可以和上面说到的交换机做简单对比:
| 名称 | 工作层次 | 转发依据 | 主要功能 |
|---|---|---|---|
| 交换机 | 数据链路层 | MAC地址(物理地址) | 用于组建局域网 |
| 路由器 | 网络层 | IP地址(网络地址) | 将局域网相互连接起来,或者接入Internet;分割广播域;提供防火墙 |
总结: 路由器实现了不同网络之间的数据转发,交换机实现了特定网络内的数据交换。
# ARP协议
上面说到,同一子网下计算机发送数据包时,包内要确定接收方的MAC地址,那么我们要怎么得到接收方的MAC地址呢?这里就需要通过ARP协议了。
ARP协议会通过广播的形式,给同一子网下的所有计算机发送一个数据包。这个数据包会包含接受者的ip地址,接受者收到这个数据包后,会取出ip地址与自身的ip地址做对比,相同则会把自身的MAC地址返回给发送者,不同则会丢弃该数据包。
这里有个问题,上面在广播中说到,计算机接收数据包时是根据包中接收者的MAC地址是否是自身来判断是否接收该数据包。那ARP协议也是通过广播的形式进行数据传送的,为什么会被计算机所接收呢?
原因是ARP协议发送的数据包中,MAC地址这里填入了一个特殊的 MAC地址,当接收数据的计算机看见这个特殊的 MAC地址 后,就知道是ARP协议在询问 MAC地址了。
在不同子网的情况下,询问 MAC地址 则是将数据包发送给网关,让网关来进行转发。
# 运输层
通过上面几层的相互协调,数据已经可以在计算机中相互传输了。但这还不够,当接收计算机接收到数据后,应当将数据发送给哪个应用程序呢,这又是一个新问题。
此时,名叫端口的靓仔登场了,当发送数据的计算机发送数据时,还需要指定一个端口,让特定的应用程序来处理这些数据。端口的范围是:0 ~ 65535,其中前1023个端口被系统应用所占用。
所以运输层的功能就浮现了,它是用来建立端口与端口之间的通信的。
有了IP和端口之后,计算机之间才能准确的进行通信。但日常工作中访问有些ip的时候并没有指定端口号,那是因为有些传输协议设定了一些默认端口,比如http的默认端口是80,https的是443。这些端口信息会包含在数据包里。
# 端口号
同一个端口不会同时出现,传输层通过辨认端口号来确认应用。但是只靠端口号识别通信是不够的。需要采取五个信息来识别一个通信,分别是源 IP 地址,目标 IP 地址,协议号,源端口号,目标端口号。两个包中只要任何一个信息不同就不是同一个通信。
# UPD协议
UDP协议是传输层最常见的两大协议之一,全称是用户数据报协议,是一种无连接的协议,是用于处理数据包的协议。
UDP数据包分为标头(8个字节)和数据(加标头不超过65535个字节)组成,它放在IP数据包的数据之中,标头主要包含发出端口和接收端口。
UPD协议的主要特点(参考UDP协议-看这篇就够了 (opens new window)):
- UDP 是无连接的,即发送数据之前不需要建立连接(发送数据结束时也没有连接可释放),减少了开销和发送数据之前的延时,同时它也是数据报文的搬运工,不会对数据报文进行任何的拆分和拼接操作。
- 不可靠性,UDP使用尽最大努力交付,发送方不关心接收方是否正确接收到数据(不保证可靠交付),与之相对好处是主机不需要维持复杂的连接状态表。ps: 连连接都不需要建立,能有锤子可靠性。
- 面向报文,发送方的 UDP 对应用程序交下来的报文,在添加首部后就向下交付 IP 层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。因此,应用程序必须选择合适大小的报文。
- 具有单播、多播、广播,UDP 支持一对一、一对多、多对一和多对多的交互通信。
- 首部开销小,只有8字节,相比 TCP 的至少20字节要少得多,在传输数据报文时更高效。
- 没有拥塞控制,网络出现的拥塞不会使源主机的发送速率降低。这对某些实时应用是很重要的。
# TCP协议
TCP就是传输层的另外一个重要协议了,它的全称是传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。
UPD协议的主要特点(参考TCP协议详解 (opens new window)):
- TCP 是面向连接的运输层协议,应用程序在使用 TCP 协议之前,必须先建立 TCP 连接。在传送数据完毕后,必须释放已经建立的 TCP 连接。
- 点对点连接,每一条 TCP 连接只能有两个端点,每一条 TCP 连接只能是点对点的(一对一)。
- TCP 提供可靠交付的服务。通过 TCP 连接传送的数据,无差错、不丢失、不重复,并且按序到达。
- 面向字节流。TCP 中的“流”指的是流入到进程或从进程流出的字节序列。
- TCP 提供全双工通信。TCP 允许通信双方的应用进程在任何时候都能发送数据。TCP 连接的两端都设有发送缓存和接受缓存,用来临时存放双向通信的数据。
# 建立TCP连接(三次握手)
建立连接的过程就是,确认双方具有发送能力和接收能力。
建立连接前,客户端和服务端都处于CLOSED状态。
服务端开始监听某个端口,进入LISTEN状态。
第一次握手:客户端开始发起连接,发送SYN(将SYN位置为1,Sequence Number为x),进入SYN-SENT状态,等待服务端的确认。
第二次握手:服务端接收到客户发送的连接请求,需要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1)。同时自身也要发送SYN请求信息(将SYN位置为1,Sequence Number为y),服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,进入SYN-RCVD。
第三次握手:客户端收到服务端的回复的SYN+ACK报文段,然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,发送完毕后,客户端和服务端都会进入ESTABLISHED状态。
注意:
- SYN 是需要消耗一个序列号的,下次发送对应的 ACK 序列号要加1,为什么呢?只需要记住一个规则:
凡是需要对端确认的,一定消耗TCP报文的序列号。
- SYN 需要对端的确认, 而 ACK 并不需要,因此 SYN 消耗一个序列号而 ACK 不需要。
- 建立TCP连接最少要进行三次握手的过程。根本原因是:两次握手无法确认客户端的接收能力。
- 三次握手的过程中只有第三次可以携带数据,前两次则不可以。原因是如果前两次握手可以携带数据,那么只要在第一次握手的过程中在SYN报文中放入大量数据,服务器就需要花费大量的时间和内存去处理这些数据,这增大了服务器被攻击的可能性。第三次握手的时候,客户端已经处于ESTABLISHED状态,并且已经能够确认服务器的接收、发送能力正常,这个时候相对安全了,可以携带数据。
# 关闭TCP连接(四次挥手)
断开连接时,客户端和服务端都处于ESTABLISHED状态。
第一次挥手:客户端向服务端发送FIN报文,设置Sequence Number,请求关闭连接,随后进入FIN-WAIT-1状态,注意这时候客户端同时也变成了half-close(半关闭)状态,即无法向服务端发送报文,只能接收。
第二次挥手:服务端收到了客户端发送的FIN报文,向客户端回复一个ACK报文段,Acknowledgment Number为Sequence Number加1(服务端表示:我同意你的关闭请求);此时服务端进入CLOSED-WAIT状态,客户端接收到报文后进入FIN_WAIT_2状态。
第三次挥手:服务端向客户端发送FIN报文,请求关闭连接,同时自身进入LAST-ACK状态。
第四次挥手:客户端接收到服务端发送的FIN报文后,想服务端回复ACK报文段,随后进入TIME_WAIT状态,服务端收到ACK报文后,就此关闭连接。客户端需要等待足够长的时间后具体为2MSL(Maximum Segment Lifetime,报文最大生存时间)依然没有收到回复,则证明ACK报文已到达,服务端端已正常关闭,随后自身也关闭连接,否则客户端会重新发送ACK报文。
附上TCP报文中FIN报文段所处位置
注意:
为什么等待2MSL? 如果不等待,直接关闭连接,假如此时服务端还有很多数据包在发往客户端的路上,客户端的端口被新的应用占据,此时就会接收到很多无用的数据包,造成数据混乱。所以最好还是等服务端发送的数据包全部被接收后再关闭连接启动新应用。
- 至于为什么是2MSL,则是因为1MSL确保四次挥手中主动关闭方最后的 ACK 报文最终能达到对端。 1MSL确保对端没有收到 ACK 重传的 FIN 报文可以到达。
为什么是四次挥手而不是三次?
因为服务端在接收到FIN, 往往不会立即返回FIN, 必须等到服务端所有的报文都发送完毕了,才能发FIN。因此先发一个ACK表示已经收到客户端的FIN,延迟一段时间才发FIN。这就造成了四次挥手。
如果是三次挥手,等于说服务端将ACK和FIN的发送合并为一次挥手,这个时候长时间的延迟可能会导致客户端误以为FIN没有到达客户端,从而让客户端不断的重发FIN。
此处参考掘金神三元文章(建议收藏)TCP协议灵魂之问,巩固你的网路底层基础 (opens new window)
综上UDP和TCP的区别可以简单概况为:TCP是一个面向连接的、可靠的、基于字节流的传输层协议。而UDP是一个面向无连接的传输层协议。
具体对比:
| 对比 | UDP | TCP |
|---|---|---|
| 是否连接 | 无连接 | 面向连接 |
| 是否可靠 | 不可靠传输,不使用流量控制和拥塞控制 | 可靠传输,使用流量控制和拥塞控制 |
| 连接个数 | 支持一对一,一对多,多对一和多对多通信 | 只能一对一通信 |
| 传输方式 | 面向报文 | 面向字节流 |
| 首部开销 | 首部开销小,仅8字节 | 首部最小20字节,最大60字节 |
| 适用场景 | 适用于实时应用 ( IP电话、视频会议、直播等 ) | 适用于要求可靠传输的应用,例如文件传输 |
总结:
- TCP向上层提供面向连接的可靠服务 ,UDP向上层提供无连接不可靠服务
- 虽然 UDP 并没有 TCP 传输来的准确,但是也能在很多实时性要求高的地方有所作为
- 对数据准确性要求高,速度可以相对较慢的,可以选用 TCP
# 应用层
应用层是分层模型的最顶层,也是最接近我们用户的,它直接和应用程序对接并提供常见的网络应用服务。在传输层通过TCP/UDP协议可以传递各种程序的的数据包,要想解析这些数据包,就需要有各种协议来规定这些数据的格式,这样才能对应协议来解析出传输过来的各种数据包。
常见的协议有:我们浏览网页时用到的HTTP协议,域名解析时用到的DNS协议,发送邮件时的SMTP协议,文件传输时的FTP协议等等。
回到开篇那道面试题,这里就涉及到DNS协议和HTTP协议。
- 01
- 2021/10/23 00:00:00
- 02
- 2021/07/04 15:26:36
- 03
- 2021/06/17 21:05:23
