网络原理——TCP/UDP/IP

发布于:2025-09-02 ⋅ 阅读:(13) ⋅ 点赞:(0)

网络原理——TCP/IP



应用层

我们之前写了最基本的java socket,要知道,我们之前所写的所有代码都在应用层,都是为了完成某项业务,例如:翻译等等。我们讲解完基本的TCP/IP协议后,我们单独进行讲解。

传输层

  • 负责数据能够从发送端传输接收端

再谈端口号

  • 端口号,标识了一个主机上进行通信的不同的应用程序
  • 在TCP/IP协议中,用源端口号,源IP,目的端口号,目的IP,协议号,这样一个五元组来标识一个通信

端口号范围划分

  1. 0 - 1023:知名端口号,留作计算机特殊用途
  2. 1024 - 65535:普通端口号,操作系统动态分配的端口号

认识知名的端口号

有些服务器是非常常用的,为了使用方便,人们约定一些常用的服务器,都是用以下这些固定的端口号:

  • ssh服务器,使用22端口
  • ftp服务器,使用21端口
  • telnet服务器,使用23端口
  • http服务器,使用80端口
  • https服务器,使用443

UDP协议

UDP协议格式

在这里插入图片描述

  • 16位UDP报文长度:表示整个UDP的大小,16位二进制数字范围是0 - 65535,所以UDP大小范围为0 - 65535个字节
  • 16位UDP校验和:用于检查数据传输是否出错的情况

详解校验和

  • 校验和,其实本质上也是一个字符串,体积比原始的数据要更小,又是通过原始的数据生成的。原始数据相同,得到的校验和就一定相同。反之,校验和相同,原始数据大概率相同(理论上会存在不同的情况,实际的概率非常低,可以忽略不计)

如何基于校验和来完成数据校验?

  1. 发送方,把要发送的数据整理好(称为 data1),通过一定的算法,计算出校验和 checksum1
  2. 发送方把 data1 和 checksum1 一起通过网络发送出去。
  3. 接收方收到数据,收到的数据称为 data2(数据可能和 data1 就不一样了),收到数据 checksum1
  4. 接收方再根据 data2 重新计算校验和(使用相同的算法),得到 checksum2
  5. 对比 checksum1 和 checksum2 是否相同。如果不同,则认为 data2 和 data1 一定不相同
    如果 checksum1 和 checksum2 相同,则认为 data1 和 data2 大概率是相同的(理论上存在不同的可能性,概率比较低,工程上忽略不计)

通过上面的方式,就能发现数据传输出错~~

  • 计算校验和,有很多种算法。此处 UDP 中使用的是 CRC 算法(循环冗余算法)

  • 把当前要计算校验和的数据,每个字节,都进行累加,把结果保存到这个 2 个字节的变量中,如果过程中如果累加溢出,也没关系。如果中间某个数据,出现传输错误,第二次计算的校验和就会和第一次不同~~

  • CRC 这个算法其实不是特别的靠谱,导致两个不同的数据,得到相同的 crc 校验和的概率比较大。前一个字节恰好少 1,后一个字节恰好多 1。这种情况概率确实不大,但是确实也还是有这方面的风险。

  • md5 / sha1 算法(就只介绍 md5)

  • 这里有一系列的公式,来完成 md5 的计算(你们不需要考虑公式是怎样的,是一个数学问题),但我们需要知道 md5 的特点

  1. 定长,无论你原始数据多长,计算得到的 md5,都是固定长度。
    校验和本身就不应该很长,要不然不方便网络传输

  2. 分散,给两个不同的数据,哪怕绝大部分内容都一样,只要其中一个字节不同,得到的 md5 也都会差异很大。md5 也非常适合作为 hash 算法

  3. 不可逆
    给你一个原始数据,计算 md5,非常容易。给你 md5,还原出原始数据,计算量非常大,以至于于超出了现有计算机的算力上限,理论上是不可行的。md5 也可以应用在一些密码学场景中。

md5 在工作中非常常用,大家一定要熟悉这几个基本特点

基于UDP的应用层协议

  • NFS: 网络文件系统

  • TFTP: 简单文件传输协议

  • DHCP: 动态主机配置协议

  • BOOTP: 启动协议(用于无盘设备启动)

  • DNS: 域名解析协议

当然,也包括你自己写UDP程序时自定义的应用层协议

TCP协议

TCP协议格式

在这里插入图片描述

  • 源/目的端口号:表示数据是从哪个进程来,到哪个进程去;
  • 32位序号/32位确认号:后面详细讲;
  • 4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个4字节);所以TCP头部最大长度是15 * 4 = 60
  • 6位标志位:
    • URG:紧急指针是否有效
    • ACK:确认号是否有效
    • PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走
    • RST:对方要求重新建立连接;我们把携带RST标识的称为复位报文段
    • SYN:请求建立连接;我们把携带SYN标识的称为同步报文段
    • FIN:通知对方,本端要关闭了,我们称携带FIN标识的为结束报文段
  • 16位窗口大小:后面再说
  • 16位校验和:发送端填充,CRC校验.接收端校验不通过,则认为数据有问题.此处的检验和不光包含TCP首部,也包含TCP数据部分.
  • 16位紧急指针:标识哪部分数据是紧急数据
  • 40字节头部选项:暂时忽略

确认应答

  • 问题:信息出现丢失;出现后发先至的情况
  • 解决:确认应答报文和发出的数据,可以对应,不要出现歧义;确保后发先至的情况,应用也可以按正常顺序读取数据

在这里插入图片描述
注意:

  • 序号按照字节编号 → 描述数据先后顺序

  • TCP 报头的序号,是这一次传输的载荷数据中第一个字节序号,剩下序号需要依次推出

  • 通过特殊的 ack 数据包,里面携带的 “确认序号” 告诉发送方,哪些数据已经被确认收到了。此时发送方,就心中有数了,就知道了自己刚发的数据是到了还是没到 => 可靠传输

在这里插入图片描述

数据重传

  • 问题:若网络传输中,出现丢包的情况,发送方无法接收到ACK
  • 原因:网络堵塞
  • 丢包:有可能丢的是数据,也有可能是ACK
  • 解决:重新传输数据(设置重传时间)
  1. 初始的等待时间,是可配置的,不同的系统上都不一定一样,也可以通过修改一些内核参数来引起这里的时间变化
  2. 等待的时间,也会动态变化。每多经历一次超时,等待时间都会变长。

情景:

  • A -> B 发了一条数据,第一次,A 等待 ACK 的时间,假设是 50ms此时如果达到 50ms,还没有 ack,A 就重传。当 A 重传的数据,还是没有收到 ack,第二次等待的时间就会比第一次更长拉长也不是无限拉长,重传若干次时,时间拉长到一定程度,认为数据再怎么重传也没用了,就放弃 tcp 连接(准确的说是会触发 tcp 的重置连接操作)

对重复数据的传输:

  • 其实 TCP 已经非常贴心的帮我们把这个问题解决了TCP 会有一个“接收缓冲区”就是一个内存空间,会保存当前已经收到的数据,以及数据的序号。接收方如果发现,当前发送方发的数据,是已经在接收缓冲区中存在的(收到过的重复数据了,接收方就会直接把这个后来的数据给丢弃掉,确保应用程序进行读取的时候,读到的是只有一条数据,不会重复

连接管理

1.握手:

正常情况下,TCP经过三次握手建立连接,四次挥手断开连接

  • 握手🤝:会由发送端主动发送一个没有业务数据的数据包,接收端也会返回一个没有业务的数据包和ACK,然后发送端再发送一个ACK,然后双方就构成了“逻辑”上的连接(这个没有业务数据的数据包也被称为“同步报文段”——SYN)

在这里插入图片描述

在这里插入图片描述

  • 三次握手的核心作用:
  1. 确认当前网络是否流畅
  2. 让双方都能确认自己的发送和接收能力正常
  3. 在握手的过程中,针对一些重要的参数,进行协商

注意⚠️:

  • 有的时候,网络如果不太好,客户端和服务器之间可能会连接断开,再重新建立连接。重连的时候,就可能在新的连接好了之后,旧连接的数据姗姗来迟。这种迟到的数据,应该要丢弃掉的!

在这里插入图片描述
2. 挥手:

  • 建立连接:客户端主动发起
  • 断开连接:客户端和服务器都可以主动发起

具体流程:

  • TCP 四次挥手是关闭连接的过程,流程如下:
  1. 第一次挥手(FIN):客户端发送带有 FIN 标志的报文,告知服务器“我要关闭数据发送了”,进入 FIN - WAIT - 1 状态
  2. 第二次挥手(ACK):服务器收到 FIN 后,回发 ACK 确认报文,告诉客户端“我知道你要关了”,进入 CLOSE - WAIT 状态;客户端收到 ACK 后,进入 FIN - WAIT - 2 状态
  3. 第三次挥手(FIN):服务器数据发送完毕,发送带有 FIN 标志的报文,告知客户端“我也准备好关闭了”,进入 LAST - ACK 状态
  4. 第四次挥手(ACK):客户端收到 FIN 后,回发 ACK 确认报文,进入 TIME - WAIT 状态;服务器收到 ACK 后,进入 CLOSED 状态;客户端等待一段时间(2 倍 MSL)后,也进入 CLOSED 状态,连接彻底关闭

在这里插入图片描述

在这里插入图片描述
问题1:

  • 为什么第二次和第三次挥手合并呢?
  • ACK 是内核响应的. B 收到 FIN, 就会立即返回 ACK
  • 第二个 FIN 是应用程序的代码触发. B 这边调用了 close 方法才会触发 FIN
    clientSocket.close();从服务器收到 FIN (同时返回 ACK), 再到执行到 close 发起 FIN, 这中间要经历多少时间,经历多少代码,是不确定的!(看你代码是咋写的)FIN 就会在 socket 对象 close 的时候,被发起.可能是手动调用 close 方法,也可能是进程结束.
  • 像前面的三次握手,ACK 和第二个 syn 都是内核触发的,同一个时机,可以合并

问题2:

  • 是否意味着,如果我这边代码 close 没写 / 没执行到,是不是第二个 FIN 就一直发不出去?(有可能的)
  • 如果是正常的四次挥手,“好聚好散”,正常的流程断开的连接。
    如果是不正常的挥手(没有挥完四次),异常的流程断开连接,(也是存在的)

在这里插入图片描述
问题1:

  • TIME_WAIT的作用是什么?
  • 如果最后一个 ACK 丢了,站在 B 的角度,B 就会触发超时重传,重新把刚才的 FIN 传一遍。如果 B 才没有进入 TIME_WAIT 状态,就意味着 A 这个时候就已经真的释放连接了。此时重传的 FIN 也就没人处理,没人能返回 ACK 了,B 永远也收不到 ACK 了。
  • A 这边使用 TIME_WAIT 状态进行等待,等待的这个时间,就是为了处理后续 B 重传的 FIN。此时有重传的 FIN 来了,就可以继续返回 ACK 了,B 这边的重传 FIN 才有意义。

问题2:

  • TIME_WAIT 等待时间是多长?
  • 假设网络上两个节点通信消耗的最大时间为 MSL
    此时 TIME_WAIT 的时间就是 2 × MSL

解释:

  • 可配置的参数(数值也是拍脑门出来了)
    已经是上限了,绝大部分的数据包也不会达到这个时间的,都会比这个时间短很多

滑动窗口

  • 前三个机制,都是在保证 tcp 的可靠性。TCP 的可靠传输,是会影响传输的效率的。(多出了一些等待 ack 的时间,单位时间内能传输的数据就少了)
  • TCP想通过“滑动窗口”,提高效率
  • 滑动窗口,就让可靠传输对性能的影响,更少一些。TCP 只要引入了可靠性,传输效率是不可能超过 没有可靠性的 UDP 的。TCP 这里的 “效率机制” 都是为了让 影响更小,缩短和 UDP 的差距
  • 缩短确认应答的等待时间

在这里插入图片描述

  • 批量传输数据
    不等 ack 回来, 直接再发下一个数据
    批量传, 也不是“无限的”传输.
    批量传输也是存在一定的上限的. 达到上限之后, 再统一等 ack
    不等的情况下, 批量最多发多少数据, 这个数据量, 称为“窗口大小”

在这里插入图片描述

  • 当前 A -> B 是批量的发了四份数据
    此时 B 也要给 A 回应四个 ACK
    此时 A 已经达到窗口大小,再收到 ACK 之前,不能继续往下发了
    需要等待有 ACK 回来了之后,才能继续往下发
  • 这里是怎么继续发的?
    是等四个 ack 都回来了,再继续发四条?
    还是回来一个 ack 就继续发一个呢?√
    回来一个 ack,就立即继续发一个
    窗口越大,等待的 ack 越多,此时传输效率也就越高

丢包问题

  1. 数据包到达,ACK丢了
    在这里插入图片描述
  • 这种情况, 不需要任何重传, 没事的

  • 确认序号, 表示的含义是, 当前序号之前的数据, 已经确认收到了.
    下一个你应该从确认序号这里, 继续发送.

  • 如果 1001 这个 ack 丢了, 但是 2001 ack 到了.
    2001 之前的数据都已经确认传输成功了, 涵盖了 1001 的情况!!!

  1. 数据包丢了

在这里插入图片描述

  • 当某一段报文段丢失之后,发送端会一直收到 1001 这样的 ACK,就像是在提醒发送端“我想要的是 1001”一样;
  • 如果发送端主机连续三次收到了同样一个“1001”这样的应答,就会将对应的数据 1001 - 2000 重新发送;
  • 这个时候接收端收到了 1001 之后,再次返回的 ACK 就是 7001 了(因为 2001 - 7000 接收端其实之前就已经收到了,被放到了接收端操作系统内核的接收缓冲区中;
    这种机制被称为“高速重发控制”(也叫“快重传”)

具体优化:

  • 如果通信双方,传输数据的量比较小,也不频繁,就仍然是普通的确认应答和普通的超时重传。
    如果通信双方,传输数据量更大,也比较频繁,就会进入到滑动窗口模式,按照快速重传的方式处理。

  • 通过滑动窗口的方式传输数据,效率是会提升的。
    窗口越大,传输效率就越大。(一份时间,等待的 ack 更多了,总的等待时间更少了)

  • 滑动窗口,设置的越大,越好嘛?
    如果传输的速度太快,就可能会使接收方,处理不过来了。此时,接收方也会出现丢包,发送方还得重传……

TCP 前提是可靠性,可靠性的基础上,再提高传输效率

流量控制

接收端处理数据的速度是有限的。如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应。

因此 TCP 支持根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫做流量控制(Flow Control);

  • 接收端将自己可以接收的缓冲区大小放入 TCP 首部中的“窗口大小”字段,通过 ACK 端通知发送端;
  • 窗口大小字段越大,说明网络的吞吐量越高;
  • 接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端;
  • 发送端接受到这个窗口之后,就会减慢自己的发送速度;

如果接收端缓冲区满了,就会将窗口置为 0;这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端

在这里插入图片描述

  • 接收缓冲区剩余空间大小
    (这里是否是最大只能表示 64k 呢?其实不是的)
    TCP 报头中,选项部分里有一项是叫做
    “窗口扩展因子”
    通过扩展因子,就可以让窗口大小
    表示一个更大的值

在这里插入图片描述

拥塞控制

  • 流量控制,是考虑的接收方的处理能力。不仅仅是接收方,还有你整个通信的路径。拥塞控制,就是考虑 / 衡量 通信过程中中间节点的情况

  • 关键问题:
    接收方的处理能力,很方便进行量化。
    由于中间节点,结构更复杂,更难以直接的进行量化。
    因此就可以使用 “实验” 的方式,来找到个合适的值。

  • 让 A 先按照比较低的速度先发送数据 (小的窗口)
    如果数据传输过程非常顺利,没有丢包。
    再尝试使用更大的窗口,更高的速度进行发送。(一点一点变化)
    随着窗口大小不停的增大,达到一定程度,可能中间节点就会出现问题了。此时这个节点就可能会出现丢包。
    发送方发现丢包了,就把窗口大小调小。此时如果发现还是继续丢包,继续缩小。如果不丢包了,就继续尝试 或变大

  • 再这个过程中,发送方不停的调整窗口大小,逐渐达成 “动态平衡”
    这种做法,就相当于把中间节点,都视为 “整体”,通过实验的方式,来找到中间节点的瓶颈在哪里~~

具体图像:
在这里插入图片描述
改进后的图像:
在这里插入图片描述

  • 改进措施:不是让速度直接归零,直接从慢启动开始。而是有一定的初速度,忽略指数增长的过程

在这里插入图片描述

延迟应答

  • A 把数据传给 B,B 就会立即返回 ack 给 A [正常]
    也有的时候,A 传给 B,此时 B 会一等会再返回 ack 给 A [延迟应答]
    本质上也是为了提升传输效率。

  • 发送方的窗口大小,就是传输效率的关键。

  • 流量控制这里,就是根据接收缓冲区中的剩余空间,来决定发送速率的。
    如果能够有办法,让这个流量控制得到的窗口更大点,发送速率就更快点
    (大的前提,能够让接收方还是能处理到过来的)
    延时返回 ack,给接收方更多的时间,来读取接收缓冲区的数据
    此时接收方读了这个数据之后,缓冲区剩余空间,变大了~~
    返回的窗口大小也就更大了。

  • 初始情况下,接收缓冲区剩余空间是 10kb,如果立即返回 ack,返回了 10kb 这么大的窗口。
    如果延时 200ms 再返回,这 200ms 的过程中,接收方的应用程序的,又读了 2kb,
    此时,返回的 ack,就可以返回 12kb 的窗口了。

捎带应答

在延迟应答的基础上, 我们发现, 很多情况下, 客⼾端服务器在应⽤层也是 “⼀发⼀收” 的. 意味着客⼾端给服务器说了 “How are you”, 服务器也会给客⼾端回⼀个 “Fine, thank you”;

那么这个时候ACK就可以搭顺⻛⻋, 和服务器回应的 “Fine, thank you” ⼀起回给客⼾端

面向字节流

  • 这里有一个重要的问题——粘包问题(这不是TCP独有的,而是所有面向字节流的机制都有类似的情况)
  • 此处的“包”是指应用层数据包。如果同时有多个应用层数据包被传输过去,此时就容易出现粘包问题

在这里插入图片描述

  • 目前,接收缓冲区中,这三个应用层数据包的数据,就是以字节的形式紧凑在一起的。接收方的应用程序,读取数据的时候,可以一次读一个字节,也可以读两个字节,也可以读 N 个字节……

  • 但是最终的目标是为了得到完整的应用层数据包。B 应用程序,就不知道,缓冲区里的数据,从哪里到哪里是一个完整的应用数据包了

如何解决粘包问题呢?

  1. 引入分隔符
  2. 引入长度

在这里插入图片描述

  • 应用程序在读取数据的时候,就可以持续读取数据,直到遇到分隔符为止

在这里插入图片描述

  • 应用程序在读取数据的时候,可以先读取两个字节,得到数据包的长度,再根据这个长度,继续读取对应字节个数

但是一般的自定义应用层协议格式,xml,json和protobuffer,本身明确了包的界限

异常情况

如果在使用TCP的过程中,出现意外,会如何处理?

  1. 进程崩溃
  • 进程没了,异常终止了。文件描述符表,也就释放了。相当于调用 socket.close()。此时就会触发 FIN,对方收到之后,自然就会返回 FIN 和 ACK,这边再进行 ACK(正常的四次挥手断开连接的流程)
  • TCP 的连接,可以独立于进程存在(进程没了,TCP 连接不一定没)
  1. 主机关机(正常)
  • 在进行关机的时候,就是会先触发强制终止进程操作 (相当于 1)
  • 此时就会触发 FIN,对方收到之后,自然就会返回 FIN 和 ACK。不仅仅是进程没了,整个系统也可能关闭了. 如果在系统关闭之前,对端返回的 ACK 和 FIN 到了,此时系统还是可以返回 ACK,进行正常的四次挥手的. 如果系统已经关闭了,ACK 和 FIN 迟到了,无法进行后续 ACK 的响应. 站在对端的角度,对端以为是自己的 FIN 丢了,重传 FIN. 重传几次都没有响应,自然就会放弃连接. (把持有的对端的信息就删了)
  1. 主机掉电(非正常)
  • 此时,是一瞬间的事情,来不及杀进程,也来不及发送 FIN,主机直接就停机了.
    站在对端的角度,对端不一定知道这个事情咋搞~~
  1. 如果对端是在发送数据(接收方掉电),发送的数据就会一直等待 ack,触发超时重传,触发 TCP 连接重置功能,发起"复位报文段"
    如果复位报文段发过去之后,也没有效果,此时就会释放连接了.

  2. 如果对端是在接收数据(发送方掉电),对端还在等待数据到达……等了半天没消息,此时其实无法区分,是对端没消息,还是对方挂了
    TCP 中提供了心跳包机制(形象的比喻)
    接收方也会周期性的给发送方发起一个特殊的,不携带业务数据的数据包,并且期望对方返回一个应答.
    如果对方没有应答,并且重复了多次之后,仍然没有,就视为对方挂了,此时就可以单方面释放连接了.

4.网线断开

  • 当前假设,是 A 正在给 B 发送数据,一旦网线断开,
    A 就相当于就会触发超时重传 -> 连接重置 -> 单方面释放连接.
    B 就会触发心跳包 -> 发现对端没响应 -> 单方面释放连接.

控制位字段

标志位 作用 配合字段 / 规则 典型场景
URG(Urgent,紧急) 标记报文段中存在需优先处理的 “紧急数据” 紧急指针(指示紧急数据结束位置) 远程登录时,用户按下 Ctrl + C 发送中断信号,数据被标记为紧急数据,URG 置 1,让接收方优先处理
ACK(Acknowledgment,确认) 确认已收到数据,是 TCP 可靠传输的核心标志之一 ACK = 1 时,确认号字段有效(表示 “期望接收的下一个字节序号”);ACK = 0 时,确认号无意义 正常数据传输中,接收方收到数据后,发送 ACK = 1 的报文,告知发送方 “已收到 xx 之前的数据,期待下一个是 xx”
PSH(Push,推送) 要求接收方立即将数据递交给应用层,不等待接收缓冲区填满 实时聊天、远程命令执行等低延迟需求场景,如用户在终端输入命令后,系统设置 PSH = 1,让接收方 TCP 层直接把数据推给应用层(如 Shell 程序)
RST(Reset,重置) 强制重置 TCP 连接,处理 “异常连接” 一方收到非法 TCP 报文(如目标端口未被监听),回复 RST = 1 的报文强制对方关闭连接;连接超时后,通过 RST 快速断开 “僵死连接”
SYN(Synchronize,同步) 用于建立 TCP 连接的 “三次握手” 阶段,标记 “同步序号”(协商双方的初始序列号) 第一次握手时,客户端发送 SYN = 1 的报文,请求建立连接并同步初始序列号;第二次握手,服务端回复 SYN = 1,ACK = 1,同步自己的初始序列号并确认客户端的序列号
FIN(Finish,结束) 用于断开 TCP 连接的 “四次挥手” 阶段,标记 “本端已无数据可发送,请求关闭连接” 一方数据发送完毕,发送 FIN = 1 的报文,告知对方准备关闭连接;对方收到后回复确认,最终完成连接关闭

TCP和UDP对比

  • TCP 优势 可靠传输,适用于绝大部分场景。

  • UDP 优势 更高效率,更适合于“可靠性不敏感”,“性能敏感” 场景

  • 如果要传输比较大的数据包,TCP 更优先 (UDP 有 64KB 的限制)

  • 如果要进行 “广播传输”, 优先考虑 UDP. UDP 天然支持广播,TCP 不支持 (应用程序额外写代码实现)

网络层

IP协议

在这里插入图片描述
基本概念:

  1. 主机:配有IP地址,但是不进行路由器控制的设备
  2. 路由器:配有IP地址,又能进行路由设备控制
  3. 节点:主机和路由器的统称

协议头格式

在这里插入图片描述

  • 4位版本号(version):指定IP协议的版本,对于IPv4来说,就是4。
  • 4位头部长度(header length):IP头部的长度是多少个32bit,也就是length * 4 的字节数。4bit表示最大的数字是15,因此IP头部最大长度是60字节。
  • 8位服务类型(Type Of Service):3位优先权字段(已经弃用),4位TOS字段,和1位保留字段(必须置为0)。4位TOS分别表示:最小延时,最大吞吐量,最高可靠性,最小成本。这四者相互冲突,只能选择一个。对于ssh/telnet这样的应用程序,最小延时比较重要;对于ftp这样的程序,最大吞吐量比较重要。
  • 16位总长度(total length):IP数据报整体占多少个字节。
  • 16位标识(id):唯一的标识主机发送的报文。如果IP报文在数据链路层被分片了,那么每一个片里面的这个id都是相同的。
  • 3位标志字段:第一位保留(保留的意思是现在不用,但是还没想好说不准以后要用到),第二位置为1表示禁止分片;这时候如果报文长度超过MTU,IP模块就会丢弃报文。第三位表示“更多分片”,如果分片了的话,最后一个分片置为1,其他是0。类似于一个结束标记。
  • 13位分片偏移(fragmentation offset):是分片相对于原始IP报文开始处的偏移。其实就是在表示当前分片在原报文中处在哪个位置。实际偏移的字节数是这个值 * 8 得到的。因此,除了最后一个报文之外,其他报文的长度必须是8的整数倍(否则报文就不连续了)。
  • 8位生存时间(Time To Live, TTL):数据报到达目的地的最大报文跳数。一般是64。每次经过一个路由,TTL -= 1,一直减到0还没到达,那么就丢弃了。这个字段主要是用来防止出现路由循环。
  • 8位协议:表示上层协议的类型。
  • 16位头部校验和:使用CRC进行校验,来鉴别头部是否损坏。
  • 32位源地址和32位目的地址:表示发送端和接收端。
  • 选项字段(不定长,最多40字节):略

地址管理

  • IP 地址,是一个 32 位的整数. 2^32 => 42 亿 9 千万.
    地址,理论上来说,是不应该重复的!
  • 互联网发展到今天,能上网的设备,非常非常多的。早就超过了 42 亿 9 千万这个数字~
    最近几年很重要的概念,物联网。汽车,空调,冰箱,洗衣机… 也都能联网了.

如何解决这个 IP 地址不够用的问题呢?

  1. 方案一:动态分配 IP
    这个方案,治标不治本,提高了 IP 地址的利用率,并没有增加 IP 地址的数目.(虽然这是一个 过渡 方案,这个方案目前仍然是广泛存在的)

  2. 方案二: NAT 机制 (网络地址转换)
    本质上 让一个 IP 地址,代表一批设备.

IP地址分类:

  1. 内网 IP (局域网 IP)
    如果一个 IP 地址,是以 10.* 或者 172.16.* - 172.31.* 或者 192.168.* ( 符合上述条件之一,就是内网 IP )
    在同一个局域网内部,内网 IP 之间,不能重复.
    在不同的局域网中,内网 IP 之间,可以重复

  2. 外网 IP (广域网 IP)
    剩下的 IP 就都是外网 IP
    外网 IP 则始终不允许重复,务必唯一.

NAT技术背景

之前我们讨论了,IPv4协议中,IP地址数量不充足的问题

NAT技术当前解决IP地址不够用的主要手段,是路由器的一个重要功能

  • NAT能够将私有IP对外通信时转为全局IP,也就是就是一种将私有IP和全局IP相互转化的技术方法

  • 很多学校,家庭,公司内部采用每个终端设置私有IP,而在路由器或必要的服务器上设置全局IP

  • 全局IP要求唯一,但是私有IP不需要;在不同的局域网中出现相同的私有IP是完全不影响的

NAT IP转换过程

在这里插入图片描述

  • NAT路由器将源地址从10.0.0.10替换成全局的IP 202.244.174.37;
  • NAT路由器收到外部的数据时,又会把目标IP从202.244.174.37替换回10.0.0.10;
  • 在NAT路由器内部,有一张自动生成的,用于地址转换的表;
  • 当10.0.0.10第一次向163.221.120.9发送数据时就会生成表中的映射关系;

NAPT

  • 那么问题来了,如果局域网内,有多个主机都访问同一个外网服务器,那么对于服务器返回的数据中,目的IP都是相同的。那么NAT路由器如何判定将这个数据包转发给哪个局域网的主机?

  • 这时候NAPT来解决这个问题了. 使用IP+port来建立这个关联关系

在这里插入图片描述

  • 这种关联关系也是由NAT路由器自动维护的. 例如在TCP的情况下, 建立连接时, 就会生成这个表项; 在断开连接后, 就会删除这个表项
  • 假如port都相同,NAT设备就会修改端口号,确保数据以一一对应传回对应主机

NAT 技术的优缺点

由于NAT依赖这个转换表,所以有诸多限制:

  • 无法从NAT外部向内部服务器建立连接;
  • 装换表的生成和销毁都需要额外开销;
  • 通信过程中一旦NAT设备异常,即使存在热备,所有的TCP连接也都会断开;

但是 NAT 有一个最大的优点:不需要更新硬件设备,只更新软件,就可以解决 IP 地址不够用的问题!

网段划分

IP 地址分为两个部分,网络号和主机号

  • 网络号:保证相互连接的两个网段具有不同的标识;
  • 主机号:同一网段内,主机之间具有相同的网络号,但是必须有不同的主机号;

在这里插入图片描述

  • 不同的子网其实就是把网络号相同的主机放到一起
  • 如果在子网中新增一台主机,则这台主机的网络号和这个子网的网络号一致,但是主机号必须不能和子网中的其他主机重复
  • 相邻的局域网,由路由器连接

通过合理设置主机号和网络号,就可以保证在相互连接的网络中,每台主机的IP地址都不相同

子网掩码

  • 一个 IP 地址,哪个部分是网络号,哪个部分是主机号,不一定的
  • 子网掩码,就是用来确定网络号的

在这里插入图片描述

  • 子网掩码是一个32位的整数,例如:255.255.255.0,转化为二进制就是1111 1111 1111 1111 1111 11111 0000 0000。这里被标为1的部分就是网络号,这里的1也不一定是二十四个,根据实际的网络环境,灵活配置的。一般来说,家用路由器的子网掩码都是255.255.255.0
  • 目前介绍这种 子网掩码 的划分,是当下环境的现状

上古时期的网段划分方式

  • 上面这种,是上古时期网段划分的方式
  • 这种方式基本上见不到了

网络号具体计算

  • 子网掩码也是一个32位的正整数。通常用一串"0"来结尾
  • 将IP地址和子网掩码进行"按位与"操作,得到的结果就是网络号
  • 网络号和主机号的划分与这个IP地址是A类、B类还是C类无关

路由选择

  • 上面讲的是IP地址的管理,路由选择也是IP协议的核心功能之一

  • 路由选择,就是描述了 IP 协议(IP 数据报)转发过程

  • 而进行 IP 数据报转发的时候,每个路由器,都是无法知道,网络的“全貌”的,只知道一些局部信息。(一个路由器能知道哪些设备和它自己是相连的)
    这就意味着 IP 数据在转发过程中,是一个“探索式”“启发式”过程。
    这个过程,很难给出“最优解”只能是“较优解”。

  • 一个网络层的数据报,每次到达一个路由器,也会进行上述“问路”过程。
    每个路由器内部都有一个数据结构“路由表”,根据数据报中的目的 IP,查路由表。

  • 如果查到了(问的人,恰好知道咋走),就直接按照路由表给定的方向(从哪个网络接口进行转发),继续转发就行了。

  • 如果没查到(问的人,不知道咋走),路由表里有一个“默认的表项”(下一跳地址),按照默认的表项转发即可~~

数据链路层

以太网帧格式

  • 这里也有很多协议,常见的就是“以太网协议”

  • 通过网线/光纤来通信,使用的协议是以太网协议。以太网横跨数据链路层 + 物理层
    在这里插入图片描述

  • 源地址和目的地址是指网卡的硬件地址(也叫MAC地址),长度是48位,是在网卡出厂时固化的

  • 帧协议类型字段有三种值,分别对应IP、ARP、RARP

  • 帧末尾是CRC校验码

认识MAC地址

  • MAC地址用来识别数据链路层中相连的节点;
  • 长度为48位,及6个字节,一般用16进制数字加上冒号的形式来表示(例如: 08:00:27:03:fb:19)
  • 在网卡出厂时就确定了,不能修改. mac地址通常是唯一的(虚拟机中的mac地址不是真实的mac地址,可能会冲突;也有些网卡支持用户配置mac地址).

对比理解MAC地址和IP地址

  • IP地址描述的是路途总体的起点和终点;(关注全程)
  • MAC地址描述的是路途上的每一个区间的起点和终点;(关注相邻节点)

认识MTU

MTU相当于发快递时对包裹尺寸的限制。这个限制是不同的数据链路对应的物理层,产生的限制。

  • 以太网帧中的数据长度规定最小46字节,最大1500字节,ARP数据包的长度不够46字节,要在后面补填充位;
  • 最大值1500称为以太网的最大传输单元(MTU),不同的网络类型有不同的MTU;
  • 如果一个数据包从以太网路由到拨号链路上,数据包长度大于拨号链路的MTU了,则需要对数据包进行分片(fragmentation);
  • 不同的数据链路层标准的MTU是不同的;

MTU对IP协议的影响

由于数据链路层MTU的限制,对于较大的IP数据包要进行分包。

  • 将较大的IP包分成多个小包,并给每个小包打上标签;
  • 每个小包IP协议头的16位标识(id)都是相同的;
  • 每个小包的IP协议头的3位标志字段中,第2位置为0,表示允许分片,第3位来表示结束标记(当前是否是最后一个小包,是的话置为1,否则置为0);
  • 到达对端时再将这些小包,会按顺序重组,拼装到一起返回给传输层;
  • 一旦这些小包中任意一个小包丢失,接收端的重组就会失败。但是IP层不会负责重新传输数据;

重要应用层协议DNS

  • 域名解析系统
  • 作用:把域名翻译成IP(二者为一组键值对)

来源

  1. 最早是使用hoste文件,来维护域名与IP的映射关系
  2. 后来搭建了DNS系统(一组服务器),把映射关系保存到服务器中
  3. 为了避免高并发的情况,增加许多镜像DNS服务器(三大运营商进行管理)

特点

  1. 开源:有许多镜像服务器,用户优先访问自己最近的服务器
  2. 节流:只要请求一次,并保存到本地

网站公告

今日签到

点亮在社区的每一天
去签到