1.路由
2.路由选择算法
3.Link State
4.Distance Vector Routing
5.核心区别
1.路由
1).路由表示按照某种指标(传输延迟, 所经过的站点数目等)找到从源节点到目标节点的较好路径
注: "节点表示源子网所在的路由器"
a.较好路径: 按照某种指标较小的路径
b.指标: 站数, 延迟, 费用, 队列长度等
c.采用什么样的指标表示网络使用者希望网络在什么方面表现突出, 什么指标网络使用者比较重视
2).互联网以网络为单位进行路由
a.以网络到网络的路由等价于网络对应的路由器到其他网络对应的路由器之间的路由(到了这个路由器就是到了这个网络)

b.路由选择算法是网络层软件的一部分, 完成路由功能
3).分析网络到网络的路由为什么等价于路由器到路由器的路由
a.IP地址的层次结构
IP地址分为两部分: 网络号(网络前缀)和主机号
例如, 在IP地址192.168.1.10/24中, 前24位是网络号(即192.168.1.0), 后8位是主机号(即10)
同一个网络内的所有设备(如192.168.1.1到192.168.1.254)都具有相同的网络号
路由器通过自己的接口连接到不同的网络, 每个接口都有一个IP地址, 该地址的网络号就是它所在网络的网络号
因此, 路由器知道它连接的每个网络的网络号
b.路由表与路由聚合
每个路由器内部维护一张路由表, 路由表记录的是如何到达其他网络, 而不是到达其他主机
路由表的一条记录通常包括: "目标网络地址、子网掩码、下一跳地址(或出口接口)"
当路由器收到一个数据包时, 它会检查数据包的目标IP地址, 并确定这个IP地址属于哪个网络(通过子网掩码计算网络号)
然后, 它查找路由表中是否有到达该网络的路径; 如果有, 就将数据包转发到相应的下一跳路由器或直接发送到目标网络
2.路由选择算法
1).网络的图抽象

a.c(x, x’) = 链路的代价 (x, x’), 比如: c(w, z) = 5
b.Cost of path(x1 , x2 , x3 ,…, xp ) = c(x1 ,x2 ) + c(x2 ,x3 ) + … + c(xp-1 ,xp )
c.路由的输入: "拓扑, 边的代价, 源节点"; 输出: "源节点的汇集树"
2).汇集树(sink tree): "对于一个目的节点, 网络中的所有节点到该目的节点的最优路径构成了一棵树"

3).路由选择算法("确定从源节点到目的节点的最佳路径")的原则
a.正确性(correctness)
- 算法必须是正确的和完整的, 使分组一站一站接力, 正确发向目标站
- 完整: 目标所有的站地址, 在路由表中都能找到相应的表项; 没有处理不了的目标站地址
b.简单性(simplicity)
- 算法在计算机上应简单最优但复杂的算法, 时间上延迟很大, 不实用, 不应为了获取路由信息增加很多的通信量
c.健壮性(robustness)
- 算法应能适应通信量和网络拓扑的变化, 通信量变化, 网络拓扑的变化算法能很快适应; 不向很拥挤的链路发数据, 不向
断了的链路发送数据
d.稳定性(stability)
产生的路由不应该摇摆
e.公平性(fairness)
对每一个站点都公平
f.最优性(optimality)
某一个指标的最优, 比如: 时间, 费用等指标
4).路由算法分类
a.按运行方式分类
- 静态: 路由随时间变化缓慢
- 动态: 路由变化很快, 周期性更新; 根据链路代价的变化而变化
非自适应算法(non-adaptive algorithm): 不能适应网络拓扑和通信量的变化, 路由表是事先计算好的
自适应路由算法(adaptive algorithm): 能适应网络拓扑和通信量的变化
b.按计算方式分类: 全局和分布式算法
3.Link State
Link State是全局式路由算法, 核心思想:
"每个路由器都知晓整个网络的拓扑结构和链路费用, 然后计算出到达所有目的地的最短路径", 比如每个出租车司机都拥有一
张完整的, 最新的城市地图, 那么他们就能自己计算出到达任何目的地的最佳路线, 无需在每个路口都为别人"哪个方向好"

链路状态算法的运作可以分为以下三个关键步骤:
1).发现邻居, 建立邻接关系
a.目的: 路由器首先要搞清楚的是 —— 谁是我的直接邻居?
b.如何实现:
- 路由器在其每个启动的接口上, 周期性地向外发送HELLO分组
- 收到HELLO分组的邻居路由器会进行回复, 从而建立双向通信
- 这个过程确保了路由器能确认哪些邻居是"活跃"的
2)测量并传播链路状态信息
这是算法中最核心的一步, 包括测量和泛洪
a.测量链路成本:
路由器会测量它到每个直接邻居的"成本", 这个成本可以是一个标准值, 也可以基于带宽、延迟、负载等因素动态计算
例如, 一个常见的简单做法是: 成本 = 10^8 / 带宽 (bps); 所以, 100Mbps链路的成本是1, 10Mbps链路的成本是10
b.构建链路状态通告:
路由器将收集到的所有链路信息(我连接了哪些邻居, 到每个邻居的成本是多少)打包成一个数据单元, 称为链路状态通告
LSA就像一张名片, 上面写着"我是路由器R1, 我有一条到R2的链路, 成本是5; 还有一条到R3的链路, 成本是2"
c.泛洪:
路由器会将它生成的LSA发送给网络中所有其他的路由器, 为了高效可靠地传递, 它使用泛洪机制
- 路由器将LSA发送给所有与之建立邻接关系的邻居
- 每个收到LSA的邻居, 会检查这个LSA是否是新的(通过序列号判断)
- 如果是新的, 邻居会将其存储到自己的链路状态数据库中, 然后立即将其从所有其他接口(除了收到该LSA的那个接口)转发
出去
这个过程就像在水中投入一颗石子, 涟漪会扩散到整个水面; 通过这种方式, 一个LSA会被快速、可靠地传递到网络中的每一
个角落
3).计算最短路径
a.目的: 当所有路由器都拥有了全网的、一致的拓扑信息后, 它们就可以各自独立地计算最优路径了
b.如何实现:
- 每个路由器都将自己作为树根, 运行最短路径优先算法——最经典的就是Dijkstra算法
- Dijkstra算法会逐步找出从本路由器出发, 到达网络中所有其他节点的最短路径
- 计算的结果会形成一个最短路径树
c.路由器根据这棵树, 将到达每个目标网络的最佳路径和下一跳地址填入自己的路由表中
序号用于解决重复接收和循环泛洪
a.问题描述: 一个路由器可能会从不同的接口, 多次收到同一个LSA
b.发生原因: 泛洪的规则是"从所有接口转发, 除了收到该LSA的那个接口"; 在一个网状网络中, 这很容易形成临时的环路,
导致同一个LSA在路由器之间来回传递
c.例子: 路由器A发出一个LSA, 发给B和C; B收到后转发给C和D, C收到后也转发给B和D; 于是, B和C都会从对方那里再次收
到这个自己已经处理过的LSA
d.解决方案: "序列号"
每个LSA都带有一个唯一的、不断递增的序列号; 当路由器收到一个LSA时, 它会检查序列号; 如果这个序列号小于或等于
自己数据库中已有的该LSA的序列号, 它就丢弃这个LSA, 并不再转发; 这从根本上避免了循环和重复处理
问题一: 如何清理"僵尸"LSA?
a.场景: 假设路由器A发出了一个LSA, 然后突然断电崩溃了; 它发出的这个LSA还存在于其他所有路由器的数据库中, 由于A
已经崩溃, 它无法再发出一个新的LSA来声明"我之前发的作废了"; 这个"已死"的LSA就会一直留在大家的数据库里, 成为一
个僵尸LSA, 可能导致错误的路由
b.解决方案: "年龄到期"
任何一个持有这个LSA的路由器, 都会不断地在泛洪过程中增加它的Age值; 最终, 当这个LSA的Age达到MaxAge(3600秒)时,
路由器会执行一次特殊的"泛洪"; 这次泛洪不是为了传播信息, 而是为了"通知所有人, 这个LSA过期了, 请立即删除"; 收到
Age = MaxAge的LSA后, 所有路由器都会将它从自己的数据库中清除
这就相当于一个自动的"垃圾回收"机制, 确保了任何LSA都不会在网络中永久存在
问题二: 如何让重启的路由器快速同步?
a.场景: 路由器A重启了, 它不记得自己崩溃前使用的序列号是多少了; 如果它从一个很低的序列号(比如0)开始发送LSA,其
他路由器会因为拥有序列号更高的"旧"LSA而认为A发来的是过时信息, 从而忽略它, A就被"孤立"了
b.解决方案: 提前让旧LSA过期
- 在A重启后, 它不会立刻发出自己的LSA, 它会先等待, 听一下邻居的信息
- 同时, 在A重启的瞬间, 网络中原本属于A的那些旧LSA还在, 并且它们的Age还在不断增长
- 当A的邻居发现与A的连接恢复后, 它们会主动将自己数据库中属于A的且Age已经很大的LSA, 以Age = MaxAge的形式泛洪
回来, 目的是"询问A, 这个信息现在还有效吗?"
- A收到这个"过期"的LSA后, 就能意识到: "哦, 这是关于我自己的旧信息, 网络正在问我最新情况"; 于是, A就可以用一个
全新的序列号发出最新的LSA来回应
这样, A就顺利地重新加入了网络, 而不会因为序列号混淆而被孤立
任何一个路由器, 只要它的链路状态数据库里存储着一份LSA, 这份LSA的Age字段就会随着系统时钟的滴答声而每秒自动增加
1; 当路由器需要转发一个LSA时(即执行泛洪操作), 在将LSA放入发出去的数据包之前, 它会先把这个LSA的Age值增加一个特
定的量
LS路由选择算法("Dijkstra - 迪杰斯特拉算法")的工作原理:
a.节点标记: 每一个节点使用(D(v), p(v)) 如:(3, B)标记
- D(v)从源节点到达本节点的最优距离
- P(v)前序节点来标注

b.2类节点
- 临时节点(tentative node): 还没有找到从源节点到此节点的最优路径的节点
- 永久节点(permanent node)N’: 已经找到了从源节点到此节点的最优路径的节点
c.初始化
- 除了源节点外, 所有节点都为临时节点
- 节点代价除了与源节点代价相邻的节点外, 都为∞
d.从所有临时节点中找到一个节点代价最小的临时节点, 将之变成永久节点(当前节点)
e.对此节点的"所有在临时节点集合中的邻节点(V)"
- 如D(v) > D(w) + c(w,v), 则重新标注此点, (D(W) + C(W,V), W)
- 否则, 不重新标注
f.开始一个新的循环

a.当前节点更新完毕邻近的代价值后, 从队列中寻找代价最小的节点
b."直到待处理节点集合为空, 才会停止"
c.快速收敛就是指: 当网络发生故障或拓扑变化时, 路由器能够非常迅速(通常在几秒甚至毫秒内)地相互通告这个变化, 并
全部更新自己的路径信息, 从而避免使用已经失效的路径
4.Distance Vector Routing
a.核心思想:
每个路由器只和自己的直接邻居交流, 并且告诉对方自己知道的"远方"的情况, 而不是整个网络的完整地图
b.它维护一张表(即路由表), 这张表主要包含两类信息:
- 距离: 到达目标网络的开销(比如跳数、延迟等)
- 矢量: 方向, 也就是下一跳路由器的地址
所以, 合起来就叫"距离矢量"
距离矢量算法的工作流程:

(假设每条链路的成本都是1)
1).初始化
a.刚开始, 每个路由器只知道自己的邻居路由器
b.它们的初始路由表是这样的:
- A的路由表: 到A自己, 成本0; 到B, 成本1(下一跳是B)
- B的路由表: 到A, 成本1(下一跳是A); 到B自己, 成本0; 到C, 成本1(下一跳是C)
- C的路由表: 到B, 成本1(下一跳是B); 到C自己, 成本0
2).定期广播整个路由表
这是DVA最关键也最"笨"的一步
每个路由器会周期性地(例如每30秒)把自己的整个路由表发送给它的每一个直接邻居
注意: "它不是发送整个网络的拓扑, 而是发送自己认为的到达所有目标的最佳路径信息"
3).接收并更新路由信息
现在, 让我们看信息是如何传递的:
a.第一次交换:
- B把自己的路由表发给A, A从B那里听到"嗨A, 我可以到达C, 成本是1"
- A心想 "B到C的成本是1, 而我到B的成本是1, 那么我通过B到达C的总成本就是 1 + 1 = 2"
- A就在自己的路由表里添加一条记录: "目标C, 成本2, 下一跳是B"
注: "距离矢量算法是根据从邻居那边获得消息知道远方的情况"
b.更新后的A的路由表:
- 到A: 0
- 到B: 1(下一跳 B)
- 到C: 2(下一跳 B)
通过这种"一传十, 十传百"的方式, 路由信息就像流言一样在网络中慢慢扩散开来
距离矢量算法的经典问题 -- 计数到无穷

1).灾难发生: 关键链路中断

2).问题开始: 罪恶的第一次更新

3).恶性循环: 计数到无穷

如何缓解这个问题?
a.水平分割: 核心规则:"从一个接口学来的路由,不再从这个接口发回去"
- 在我们的例子中,A从B那里学到了到C的路由; 那么当A给B发送更新时, 就应该省略关于C的路由
- 这样, 当B -> C断开后, B就不会再从A那里听到关于C的错误信息, 从而能立刻判断C不可达
b.毒性逆转: 水平分割的增强版, 规则: "从一个接口学来的路由,在从这个接口发回去时,将其距离设置为无穷大"
- A会明确告诉B: "你想到C? 我确实知道一条路, 但成本是无穷大"
c.触发更新: 一旦检测到链路失效, 立即发送更新, 而不是等待定时器到期; 这可以加快坏消息的传播速度
5.核心区别

a.距离矢量是"路标式导航": 你只知道"往前走到下一个路口, 然后听下一个路口的"
b.链路状态是"手机地图导航": 你手机里有了全市地图, 自己规划路线