常见的OSPF五个疑难问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了常见的OSPF五个疑难问题相关的知识,希望对你有一定的参考价值。
参考技术A常见的OSPF五个疑难问题
OSPF是运用非常多的一种路由技术,下面我和大家分享一下OSPF常见疑难问题
1、OSPF特殊区域中如果存在两个ABR,那么这两个ABR都下发缺省路由,不是会形成环路吗?
不会形成环路,当特殊区域中的ABR接收到同一区域ABR发来的带有默认路由的SLA时,它只会将其放入LSDB(LSA Database)里,但不会用其计算路由,从而避免环路。
如果OSPF路由器已经发布了含缺省路由的LSA,就不会再学习其它路由器发布的相同类型的缺省路由LSA(路由计算时不再计算其它路由器发布的相同类型的缺省路由LSA)
如果在一个NSSA区域有两个ABR,他们都会将Type7 LSA转换成Type5 LSA吗?
不会的,RFC3101中规定,当NSSA区域有多个ABR时,只有Router ID最大的ABR负责将Type7 LSA转换成Type5 LSA。
2、Virtual-link和sham-link的区别是什么?
Virtual-link是为了解决OSPF的不规则区域问题而产生的,正常情况下OSPF的所有非骨干区域都要直接和骨干区域(area0)相连,如果由于前期规划问题等原因导致某个非骨干区域必须通过另一个非骨干区域来连接骨干区域的话,就要用到virtual-link。如下图所示:为了让Area2能够和骨干区域相连,需要在R3和R2之间建立一条virtual-link。
OSPF的VPN配置下,PE2通过从远端PE1通过Mbgp学到的路由引入到OSPF后只能还原成3类/5类/7类LSA,如果CE之间存在后门链路,,作为公网mpls链路的`备份。则在CE上通过后门链路学到的路由是区域内路由,由于从MBGP学到的路由,这样就导致了数据只能通过后门链路而不会优选MPLS链路,未解决此问题产生了sham-link,sham-link的主要作用是可以还原1类和2类LSA.
3、OSPF支持多进程,那么交换机的一个接口也可以属于不同的OSPF进程吗?
不能。OSPF支持多进程是指在同一台交换机上可以运行多个不同的OSPF进程,它们之间互不影响,彼此独立,不同OSPF进程之间的路由交互相当于不同路由协议之间的路由交互。但是交换机的一个接口只能属于某一个OSPF进程。
4、OSPF GR
Graceful Restart指的是平缓重启路由器的一种功能,可以保证流量转发不中断,网络不会因为路由器的短时间重启而引起路由震荡。
路由器若不以Graceful Restart方式重启OSPF协议,与它邻接的路由器就会把它从邻居列表中删除,并通知给其他路由器,导致重新计算SPF。如果协议重启的时间很短,就会引起路由震荡。
为了避免不必要的SPF计算,当路由器以Graceful Restart方式重启OSPF协议时,会通知与它邻接的路由器它只是关闭几秒钟,马上就会恢复正常。这样,邻接路由器就不会将进行GR操作的路由器从邻居列表中删除,其他路由器也不会知道有路由器重启,这样就避免了因邻居关系改变而导致的路由震荡。
5、OSPF为什么要划分区域?
在比较大的网络中OSPF的LSA非常庞大,占用大量的存储空间。OSPF是链路状态协议,所以路由器存储的是LSA而不仅仅是路由信息。划分区域后,每个分区内的路由器所需要存储的LSA的数量会大大的减少。
链路状态算法比距离矢量算法复杂的多,在比较大的网络中计算最小生成树耗时大,CPU的负担很重。划分区域后,区域内还是采用链路状态算法,但是区域之间采用的则是距离矢量算法。
在比较大的网络中网络拓扑结构经常发生变化,使得网络经常处于“动荡”之中。网络比较大的时候,网络中拓扑发生变化的概率也会比较大,每次网络拓扑发生变化的时候,都要重新计算最小生成树。划分区域后,ABR相当于一个“大坝”,把不同区域的“动荡”隔离开来。
;Carson带你学Android:那些关于view.post() 的四大常见疑难杂症
本文主要讲解view.post() 的四大常见疑问
- 为什么view.post()能保证获取到view的宽高?
- 为什么onCreate()使用view.post()无法立刻执行任务(如获取宽高)
- 若只是创建一个 View & 调用view.post()传入要执行的任务,为什么该任务不会被执行?
- view.pos()传入的任务被执行的有效期是什么时间节点?
Carson带你学Android系列文章
Carson带你学Android:学习方法
Carson带你学Android:四大组件
Carson带你学Android:自定义View
Carson带你学Android:异步-多线程
Carson带你学Android:性能优化
Carson带你学Android:动画
常见疑问1
a. 描述
为什么view.post()能保证获取到view的宽高?
.b 原因
View.post()的原理:以Handler为基础,View.post() 将传入任务添加到 View绘制任务所在的消息队列尾部,从而保证View.post() 任务的执行时机是在View 绘制任务完成之后的。 其中,几个关键点:
-
View.post()实际操作:将view.post()传入的任务保存到一个数组里
-
View.post()添加的任务 添加到 View绘制任务所在的消息队列尾部的时机:View 绘制流程的开始阶段,即 ViewRootImpl.performTraversals()
-
View.post()添加的任务执行时机:在View绘制任务之后
所以:
-
通过View.post()添加的任务是在View绘制任务里 - 开始绘制阶段时添加到消息队列尾部的;
-
所以,View.post() 添加的任务的执行是在View绘制任务后才执行,即在View绘制流程结束之后执行。
-
即View.post() 添加的任务能够保证在所有 View绘制流程结束之后才被执行,所以 执行View.post() 添加的任务时可以正确获取到 View 的宽高。
具体源码分析请看:Android:为什么view.post()能保证获取到view的宽高?
常见疑问2
a. 描述
为什么onCreate()使用view.post()无法立刻执行任务(如获取宽高),需要在onResume()后才可获取?
.b 原因
在onCreate()时,AttachInfo还没被赋值(为null)(是在view.dispatchAttachedToWindow()才被赋值),所以会走下述源码的过程2;通过上面分析,此过程的作用仅是:保存了通过post()添加的任务,并没执行。
public boolean post(Runnable action)
// ...
// 判断AttachInfo是否为null
final AttachInfo attachInfo = mAttachInfo;
// 过程1:若不为null,直接调用其内部Handler的post ->>分析1
if (attachInfo != null)
return attachInfo.mHandler.post(action);
// 过程2:若为null,则加入当前View的等待队列
getRunQueue().post(action);
return true;
c. 实例代码演示
@Override
public void onCreate(Bundle savedInstanceState)
// 执行日志1:carsonhe oncreate()
view.post(new Runnable()
@Override
public void run()
// 执行日志2:carsonhe view.post() do something
);
@Override
protected void onResume()
// 执行日志3:carsonhe onresume()
// 输出日志展示
日志1:carsonhe oncreate()
日志3:carsonhe onresume()
日志2:carsonhe view.post() do something
常见疑问3
a. 问题描述
若只是创建一个 View & 调用它的post(),那么post的任务会不会被执行?
final View view = new View(this);
view.post(new Runnable()
@Override
public void run()
// ...
);
b. 答案
不会。主要原因是:
每个View中post() 需执行的任务,必须得添加到窗口视图-执行绘制流程 - 任务才会被post到消息队列里去等待执行,即依赖于dispatchAttachedToWindow ();
若View未添加到窗口视图,那么就不会走绘制流程,post() 添加的任务最终不会被post到消息队列里,即得不到执行。(但会保存到HandlerAction数组里)
上述例子,因为它没有被添加到窗口视图,所以不会走绘制流程,所以该任务最终不会被post到消息队列里 & 执行
c. 解决方案
此时只需要添加将View添加到窗口,那么post()的任务即可被执行
// 因为此时会重新发起绘制流程,post的任务会被放到消息队列里,所以会被执行
contentView.addView(view);
常见疑问4
a. 描述
view.pos()传入的任务被执行的有效期是多久?
b. 结论
在整个 Activity 的生命周期内都可以正常使用 View.post() 任务
c.原因
任务被执行是构造AttachInfo,所以任务释放即时释放AttachInfo (置为null)。而AttachInfo 的释放操作(置为null)是在 Activity 生命周期 onDestory 方法之后
.d 原因分析
-
目标
跟踪 AttachInfo 的释放过程(即何时置为null) -
方向
AttachInfo的赋值依赖于DecorView.dispatchAttachedToWindow(),那么释放过程,容易联想到是对应的:DecorView.dispatchDetachedFromWindow() -
具体源码分析
/**
* 入口分析:DecorView.dispatchDetachedFromWindow()
* 实际上是调用父类ViewGroup.dispatchDetachedFromWindow()
*/
void dispatchDetachedFromWindow()
// ...
final int count = mChildrenCount;
final View[] children = mChildren;
// 遍历所有childView
for (int i = 0; i < count; i++)
// 遍历所有childView & dispatchDetachedFromWindow()
// 分析1
children[i].dispatchDetachedFromWindow();
/**
* 分析1:childView.dispatchDetachedFromWindow()
*/
void dispatchDetachedFromWindow()
// ...
AttachInfo info = mAttachInfo;
// 1. 回调View.onDetachedFromWindow()
onDetachedFromWindow();
// 2. 通知所有监听View.onAttachToWindow的监听者回调onViewDetachedFromWindow()
ListenerInfo li = mListenerInfo;
final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = li != null ? li.mOnAttachStateChangeListeners : null;
if (listeners != null && listeners.size() > 0)
for (OnAttachStateChangeListener listener : listeners)
listener.onViewDetachedFromWindow(this);
// 3. 将AttachInfo置为null
mAttachInfo = null;
下面,我们将分析,什么时候调用上述入口,即DecorView.dispatchDetachedFromWindow();
此时需从 将DecorView从WindowManager中移除 开始讲起:移除 Window 窗口任务是通过 ActivityThread.handleDestoryActivity()完成。
/**
* 入口
*/
private void handleDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance)
// 关注1:回调 Activity.onDestory()
ActivityClientRecord r = performDestroyActivity(token, finishing,
configChanges, getNonConfigInstance);
// 获取当前Window的WindowManager
WindowManager wm = r.activity.getWindowManager();
// 当前Window的DecorView
View v = r.activity.mDecor;
// 关注2:通知WindowManager,移除当前 Window窗口
wm.removeViewImmediate(v);
// 此处即会释放AttachInfo
// 因为在关注1处是在回调 Activity.onDestory()后,故在整个Activity的生命周期内都可以正常使用 View.post() 任务
// 下面继续分析如何移除 ->> 分析1
/**
* 分析1:WindowManager.removeViewImmediate()
*/
public void removeViewImmediate(View view)
mGlobal.removeView(view, true);
// 调用WindowManagerGlobal的removeView()
// ->> 分析2
/**
* 分析2:WindowManagerGlobal.removeView()
*/
public void removeView(View view, boolean immediate)
// ...
// 找到保存该DecorView的下标
int index = findViewLocked(view, true);
// 找到对应的ViewRootImpl,内部的DecorView
View curView = mRoots.get(index).getView();
// 从WindowManager中移除该DecorView
// immediate 表示是否立即移除
removeViewLocked(index, immediate);
// ->> 分析3
/**
* 分析3
*/
private void removeViewLocked(int index, boolean immediate)
// 找到对应的ViewRootImpl
ViewRootImpl root = mRoots.get(index);
// 该View是DecorView
View view = root.getView();
// ...
// 调用ViewRootImpl的die
// 并且将当前ViewRootImpl在WindowManagerGlobal中移除
boolean deferred = root.die(immediate);
// ->> 分析4
/**
* 分析4
*/
boolean die(boolean immediate)
// immediate 表示立即执行
// mIsInTraversal 表示是否正在执行绘制任务
if (immediate && !mIsInTraversal)
doDie();
// ->> 分析5
// ...
/**
* 分析5
*/
void doDie()
// ...
if (mAdded)
dispatchDetachedFromWindow();
// 回调View的dispatchDetachedFromWindow
// ->> 即一开始分析的DecorView.dispatchAttachedToWindow()
// 将其从WindowManagerGlobal中移除DecorView
WindowManagerGlobal.getInstance().doRemoveView(this);
.d 最终原因 & 结论
View.post() 任务被执行的有效期是在 Activity 生命周期 onDestory()后。本质是追踪AttachInfo的释放过程(置为null)
AttachInfo的释放过程是在 将DecorView从WindowManager中移除时:回调DecorView.dispatchDetachedFromWindow(),其具体行为是:
- 回调View.onDetachedFromWindow()
- 通知所有监听View.onAttachToWindow的监听者回调onViewDetachedFromWindow()
- 将AttachInfo置为null
而上述过程是在ActivityThread.handleDestoryActivity()中回调 Activity.onDestory()之后。
至此,关于view.post()的四大常见疑问 (坑)内容讲解完毕。
总结
- 本文主要总结了常用的view.post() 的四大常见疑问
- Carson带你学Android系列文章
Carson带你学Android:学习方法
Carson带你学Android:四大组件
Carson带你学Android:自定义View
Carson带你学Android:异步-多线程
Carson带你学Android:性能优化
Carson带你学Android:动画
欢迎关注Carson_Ho的CSDN博客 与 公众号!
博客链接:https://carsonho.blog.csdn.net/
请帮顶 / 评论点赞!因为你的鼓励是我写作的最大动力!
以上是关于常见的OSPF五个疑难问题的主要内容,如果未能解决你的问题,请参考以下文章