2026-02-02-网络原理-TCP_IP
应用层
虽然有很多已经实现好的协议,但是在实际开发中依然会“自定义协议”来满足业务需求
一般情况下,是通过
JSON这个结构来传输数据的
序列化与反序列化
序列化:把对象变为结构化的字符串反序列化:把结构化的字符串转为对象
传输层
传输层主要内容就是 UDP 与 TCP
UDP
它是由源端口,目的端口,长度,校验和,载荷(应用层的全部数据)组成的
长度:占两个字节,最多表示64KB, 因此使用UDP协议的时候需要考虑数据量的大小校验和:校验数据是否正确,比如被修改或者损坏都会出现丢弃(不通知)
TCP
它是由源端口,目的端口,序号,确认序号,6位标志位,首部长度,窗口大小,校验和,应急指针,选项,数据组成的
序号:发送的序号,用来表明发送的先后顺序确认序号:存储的是最后一个序号+1, 比如传入的序号是 1-1000 那么确认序号就是 1001首部长度:请求头的长度,单位是 4个字节
确认应答
接收端接收到发送端的数据时候,会返回一个数据报用来相应,告诉发送端已经接收到了, 此时标志位
ACK会被设置为 1,当然返回的数据报载荷是空的发送端接收到接收端的
ACK返回的数据,通过“确认序号”,知道接收端接收到了哪个数据
超时重传
丢包是客观存在,所以当发生丢包后,就需要重新发送一次或者多次,达到重新传递的效果。
在一次丢包内,每次重新发送后等待的时间会逐渐变大
如何避免由于发送端没有收到确认应答而导致的数据重复发送问题?
通过阻塞队列来解决,如果队列中有数据报中的序号(或者是序号所对应的位置已经有数据了), 那么可以直接丢弃来实现去重的效果。
而且把阻塞队列进行按照特定方式(比如时间戳)排序,就可以**解决“后发先至”**的问题
后发先至指的是数据由于网络波动等原因,导致发送端晚一点发送的数据先到接收端这一个现象
连接管理
连接管理主要是建立连接(三次握手)和断开连接(四次挥手)
握手其实就是“打招呼”,里面不会传递应用层中“实质性”的数据, 它没有载荷,只是传递双方的基本信息而已,它主要的作用就是给通信双方提供必要的信息
三次握手
TCP 也会有相关的状态转换CLOSED: 软件未启动LISTEN: 服务端监听SYN_SENT: 用户端发送ACKSYN_RCVD: 服务端收到ACKESBALIED:TCP成功建立
问题:
为什么需要三次握手呢?
- 可以保证通信双方中间的通信没有太大问题
- 可以保证服务端与用户端发送与接收正常
第一次握手(用户端发送
SYN),如果此时服务端收到,这就可以表明用户端发送与服务端接收正常第二次握手(服务端同时发送
SYN和ACK),如果用户端收到,这就可以表明服务端发送与用户端接收正常第三次握手(用户端发送
ACK),将双方通信正常的信息同步给服务端 - 可以传递一些参数,比如双方的序号的起始位置,方便后续的通信
为什么序号不建议从1开始,而是使用一个“随机数”
这是为了防止这样的情况:有一个TCP数据报,由于网络波动(过了较长时间),等到了服务端,这个端口是另一个连接的了
而随机数可以比较好的缓解这个问题:通过判断数的差异,就可以判断出这个数据报是不是相对应的连接,如果不是那么就直接丢弃即可
TCP 能不能四次握手?两次呢?
四次是可以的,两次是不行。
因为三次就可以建立连接了,就算第四次什么也不做,那也是可以建立连接,但是没必要,因为这样网络开销就偏高了
两次是可以从两个角度出发:
- 从理性分析出发,那些开发的大佬都必须写为三次,如果两次就可以了,就一定会写为两次,而且应该叫“两次握手”而不是三次握手
- 从目的出发,最后一步是要让服务端知道双方可以正常通信,如果没有最后一步,那么就会缺少一步,就正常通信不了
四次挥手
同样这也有几个状态,其中 TIME_WAIT 和 CLOSE_WAIT 是比较重要的
CLOSE_WAIT: 接收方等待关闭,如果看见有大量的这个状态,那么就需要考虑接收方有没有执行close来释放资源TIME_WAIT: 发起方释放资源之前最后的等待时间
问题:
四次挥手中,中间的那两步能不能合并为一步?
可以合并,但是一般情况下不会合并
因为接收方需要处理一系列的善后工作,比如释放资源,记录日志等工作
为什么在最后发起方需要有
TIME_WAIT这个状态,而不是直接变为CLOSED?如果接收方没有收到
ACK, 那它就会发FIN,此时发起方已经释放资源了, 就自然不会发送ACK了,这就会导致接收方会一直发FIN, 这显然是不合理的。为了照顾到这个情况,
TIME_WAIT的存活时间就会设置为两倍的MSL, 这样在绝大部分场景下,都没问题MSL是表示数据从一段到另一端最大的传输时间
滑动窗口
ACK 才会发送,这个会大大降低效率那如果数据丢失了怎么办呢? 它分为两个情况:数据段丢失和 ACK 确认包丢失
TCP-滑动窗口-ACK确认包 ACK丢失,不需要重新传递,因为通过确认序号可以保证它之前的数据都是已经接收到了,发送端自然就可以不用重新发送 数据段丢失,此时接收方就会接收到多次确认序号相同的TCP-滑动窗口-数据段丢失 ACK数据报,如果达到 3 次,那么就会重新发送一份为什么是 3 次,而不是 2 次呢? 这个是实验算出来的。
比如发送方发送的顺序是
P1-P2-P3-P4,那么接收端收到的可能是P2-P3-P1-P4。 如果设置为 2 次,可能就会导致重复发送而造成的宽带浪费,而设置 4 次又会导致等待时间太长,所以选择一个折中的方法,选择 3 次
这两个处理措施就是快速重传的基础
那么 确认应答+超时重传 不就会与 滑动窗口+快速重传 有出入了吗?如何理解呢?
它们两组是相互配合,取长补短的。
确认应答+超时重传适合传输频率比较低的场景,而滑动窗口+快速重传适用于传输频率较高的场景
流量控制
发送方一直发送,如果没有反馈,那么窗口就会越来越大,速度也就越来越快
此时接收方就处理不过来了,在 ACK 的确认包里的
窗口大小这个字段来告诉发送方应该调节的窗口大小可以通过缓冲区中的 总长度-使用长度 来表示窗口大小
到了极端情况,接收方的缓冲区已经满了,那么接收方就会告诉发送方不要在发送了,此时发送方就会停止发送“有效”的数据
为了知道什么时候可以发送数据,发送方就会定期发送一个只有最基本结构的数据报(窗口探测),用来判断接收方是否可以接收新的数据报,对方可以接收,那么就会返回一个合适的窗口
拥塞控制
由于中间链路是不能定量的描述,所以会通过做实验的方式来描述当前中间流量的流通情况
- 为了防止过大导致网络堵塞的问题,刚刚开始发送速度设置一个很小的初始值
- 接着在超过
ssthresh这个变量之前,每一次都是以二倍速变快(指数增长) - 超过了
ssthresh后,增长速度就会从指数增长变为线性增长 - 如果连续三次收到相同的 ACK, 说明网络有丢包,那么就会降低发送速度
- 方法一:窗口大小减半,然后线性增长
- 方法二:窗口大小设置为很小的数,把
ssthresh设置为原来窗口一半的大小,然后重复上诉 2/3/4 步骤(已经废弃)
- 通过上面这几个步骤,窗口大小就可以维持在一个平衡的区间内
问题
拥塞控制与流量控制都是控制窗口,那么具体是以哪个为主呢?
以它们的较小值为主。如果以较大者为主,那一定会有一个不满足,这样都会浪费大量的宽带资源
延迟应答
延迟应答是提升效率的一种方式: ACK 返回之前会多等一会,让接收方多处理缓冲区的内容,这样可以使返回的窗口(流量控制)更大,增加效率。
由于缓冲区在延迟应答期间会接收发送方的数据,如果发送方发送过快,可能会导致缓冲区满了。又因为延迟应答,会导致在一定时间内都没有制约发送过快的问题,这就会导致效率不升反降的情况。
但是通过实验,发现这样的情况是少数的(类似与快排中的时间复杂度,是
,所以延迟应答还是很有必要的
如何配置延迟时间呢?
- 可以配置具体的时间,但是一定不能超过超时重传的时间
- 还可以是每请求 N 个数据报,只返回一个
ACK
携带应答
携带应答就是可以把四次挥手变为 3 次的原因
面向字节流
这里的字节流与文件IO中的字节流是一样的。
问题:如何解决粘包问题?(字节流的都有)
- 方法1: 使用特殊字符来来分割。注意:传输的数据是不能有特殊字符
- 方法2: 使用长度变量来表示当前数据的长度 这两种方法一般都会使用
异常情况
异常情况分为 进程崩溃,主机关机,主机掉电,网线断开 这几类 如果有其他类,那么就自动推理一下
进程崩溃
TCP 断开一样,都是经历四次挥手后正常断开就可以了主机关机
ACK 就结束了。此时另一个主机就会超时重传,如果超过一定次数,那么就会发送 RST,此时就会关闭连接
RST就是告诉对方己方要单方面断开连接,不会管对方是否会收到,这个仅仅是用来通知而已
主机掉电
主机掉电是突然断开电源导致电脑关机,比如使用台式机忽然停电了。 它是分为发送方断电与接收方断电
发送方断电:由于发送方是忽然断开发送信息,接收方是无法判断对方停止发送了还是断电关机了,所以需要定时发送一个数据报来检测对方是否“活着”(心跳包),如果返回TCP-异常情况-主机掉电-发送方断电 ACK那么就无事发生,如果在多次超时重传后依然没有,它就会发送RST强制关闭连接这样的类似的“心跳”机制在很多场景下都会有,比如分布式系统
接收方断电:发送方在一段时间内没收到TCP-异常情况-主机掉电-接收方断电 ACK,就会超时重传,如果多次都没有用,那么就会发送RST单方面断开连接
网线断开
网线断开和主机掉电类似,只不过是变为发送方和接收方都断电了,处理过程参考主机掉电
问题
一个进程可以绑定不同端口吗?
可以。一般情况下,软件都会有两个端口,一个是提供给普通用户使用的,另一个是给开发团队测试代码使用的
一个端口可以绑定多个进程吗?
可以。只有在源IP,源端口,目的IP,目的端口,协议这五个都一样才会触发“端口被占用”这个问题
TCP中确认应答与响应的区别?问题-确认应答与响应区别 - 确认应答是在传输层中实现的,而响应是在业务(应用层)中实现的
- 只要是
TCP, 都会确认应答,但是响应是由业务场景来决定的,如果不需要可以没有响应
网络层
网络层中最主要的就是 IP 协议,这个是分配具体路径的
IP 协议格式
版本:表明这个IP的版本号,有IPv4和IPv6首部长度:它也与 TCP 一样,是以 4 个字节为单位的,最大为 60 个字节服务类型:仅仅有四个是有效的,而且这四个只能有一个为1, 其余的必须为 0, 它们的表示意思分别为:最小延时,最大吞吐量,最高可靠性,最小成本。(仅仅了解即可)总长度:它最大为 64KB,不能变大。那么它是如何处理大于 64KB 的数据呢?它内部有自动的拆包和分包,如果大于 64KB 那么就会自动拆包和分包,把大数据分为多分小数据
标识:用来表示这个数据包是不是由同一个大数据拆分出来的,如果来自于同一个,那么它们的表示是一样的标志:里面有两个主要内容:表示是否触发拆包组包和是否是最后一个包片偏移:用来表示数据包的先后顺序的,这个是用来解决后发先至的问题生存时间(TTL):用来表示数据包的存活时长,不过里面是存放的是可以转发的次数,而不是时间。每经过一次路由器,TTL都会自动减一,如果为 0 了,那么就会自动丢弃。它是用来解决包无限转发而浪费大量宽带资源这样的情况协议:描述载荷的协议类似校验和:它是只校验首部的内容,不校验载荷IP地址:表示发送端或者接收端
IP 资源紧缺的解决方案
动态IP
顾名思义,就是每一次上网的IP 不是固定的,当你不上网的时候,就可以释放IP资源,给别人使用。
NAT 技术
NAT 是让多台设备共用一个IP 资源,它极大的缓解了IP资源紧缺的问题。
比如 A 主动给 B 发送信息,那 B 必须为有公网的IP,不能在局域网下面,A 应该在局域网内,因为如果在公网内,就不涉及 NAT 了
- A 发送
(REQUEST)的数据经过路由器,路由器将数据包中的 IP 改为公网 IP, 并且将源IP, 源端口,目的IP,目的端口这些数据保留在一张映射表内 - B 接收到了数据后,会给他响应
(RESPONSE)一个数据,然后通过映射表的数据,将数据传给A
问题:
为什么B(公网) 给 A(局域网) 发送消息就不可以?
因为此时没有映射表,数据就不清楚应该发给哪个局域网IP中的哪个端口
如果在同一个局域网内的两个不同的IP使用同一个端口发送给公网中同一个IP中的同一个端口,那如何区分数据呢?
可以给另一个IP 分配不同的端口即可
IPv6
动态IP 和 NAT 只能缓解IP资源紧张的问题,而不能解决这个问题。而IPv6 是可以有
原因:
- NAT 管理起来很麻烦,而是由于要处理映射,速度快不起来
- NAT 在套一层的情况下,顶多翻个 65535 倍,这在目前互联网发展速度来看是有点不够用的
IP 地址划分
前半部分是网络号,后半部分是主机号
特殊IP 地址
特殊IP地址分为 内网地址,环回地址
内网地址:192.168.*, 10.*, 172.16.*~172.31.*环回地址:127.*
其他:其中 0 是表示整个网段,255表示广播地址
路由选择
先要明确一点,由于网络的复杂性,一个路由器是无法获取到当前网络的所有结构,也就不能像地图那样可以获取到最佳路线,而只能获取到一个较佳的路线。
以这图为例。 比如要从永康市发送给义乌市,永康市这个路由器就不找到,就会发给金华市,在金华市这个路由器就找到义乌市这个路径,就可以把数据发给义乌市了。 (实际上,网络是一个很复杂的结构,这个仅仅是用来帮助理解学习)
路由表创建
- 可以手动创建
- 也可以是通过一些算法自动创建
数据链路层
数据链路层是管理数据在相邻两个机器上是如何通信的,类比于现实中从杭州到北京去上学,方式可以通过坐飞机,也可以坐高铁,还可以自驾
MAC地址:它是刻录在机器上的,每个机器都有唯一的一个类型:描述载荷中是什么样的数据类型,比如IPv4,IPv6数据载荷:它最大只能是1500字节(MTU),因此在网络层还需要拆包,把大的数据拆分为小数据,这样才可以在数据链路层中传输
在数据链路层中,为了知道相邻机器地址,还会有一张“转发表”,它是通过 ARP 协议,将 MAC 与 IP 给联系起来
问题:
MAC 与 IP 区别:
- 个数区别
- 在数据链路层传递的时候,每次到不同的路由器/交换机上,
MAC是都会更新,但是IP就不会更新(不考虑NAT情况下)
为什么
MAC没有资源紧缺的问题,而IP却有?MAC分配高效,IP分配低效。比如IP由于地区限制,会导致总有一部分IP是冗余的;或者由于早期IP不合理的分配,导致大量IP浪费MAC个数较多,IP个数较少。
数据链路层中除了以太网,还有哪些协议?(面试题)
- Wi-Fi
- 蓝牙
- 5G
其他内容
DNS
DNS 全称叫作域名解析器,它是用来解决 IP 记忆比较抽象的这个问题。 为了方便管理,它是交给13台 DNS 根服务器来处理。比如 www.baidu.com 就可以比较方便的获取到百度的IP地址
这里的
IP地址一般是CDN的IP地址,而不是源服务器的IP地址,这样可以增加安全性
问题:
它是如何解决高并发的问题?
- 本地缓存
- 分布式集群,比如各个运营商/厂商的镜像构建
它是如何存储的?
它是分级存储,像 com, org, net, edu, cn, us 等一级域名存储在各个的最顶层服务器,它们里面都存储着各个的一级业务所对应的二级域名的 DNS 服务器地址。
以此类推,二级域名的 DNS 服务器地址存储着三级域名的 DNS 服务器地址,...