前面通过阅读代码知道了怎样推断各个模块处理某个消息的先后顺序。那么内部是怎样实现的呢?
     每当一个模块表示对一个消息感兴趣的时候,就会调用IFloodlightProviderService(详细有Controller类实现)的addOFMessageListener方法进行注冊订阅,核心工作是由 ListenerDispatcher类来完毕:1)每次添加一个观察者的时候都会推断其是否是终结点(也就是不被其它的listener所依赖),由于终于确定这些观察者顺序的时候就是由这些终结点開始往前进行DFS遍历而得到。2)比方说ForwardingBase和Distributing
(我们自己加的。没有约束其顺序)。当它们注冊packetin消息的时候。会增加到终结点集合terminals中。所以从它们開始深度遍历的时候得到的有序集合ordering=linkdiscovery,topology,devicemanager, forwarding, distributing(这里进行了两次DFS traverse)。接下来看代码:

-------------Controller中实现IFloodlightProviderService的方法
            @Override
         public synchronized void addOFMessageListener(OFType type,
                                                       IOFMessageListener listener)
{
                //先推断与type相应的 ListenerDispatcher对象是否存在
             ListenerDispatcherOFTypeIOFMessageListener>
ldd =
                 messageListeners.get(type);
             if (ldd
== null ) {
                 ldd = new ListenerDispatcherOFTypeIOFMessageListener>();
                 messageListeners.put(type, ldd);
             }
             //注冊监听type这个消息。
             ldd.addListener(type, listener);
         }
--------------ListenerDispatcher实现(维护这些观察者,有依赖关系)

public class ListenerDispatcher <U,
extends IListener<U>>
{
    protected static Logger logger = LoggerFactory.getLogger(ListenerDispatcher. class );
    List<T> listeners = null;
    //每一个OF msg都有唯一的ListenerDispatcher对象。观察者存在listeners链表中
   
    //从listener这个观察者開始,根据有没有监听者在他之前,进行深度优先遍历
    //终于有序序列存在ordering中。visited用于存已经訪问过的terminal
listener。
    private void visit(List<T>
newlisteners, U type, HashSet<T> visited,
                       List<T> ordering,
T listener) {
        if (!visited.contains(listener))
{
            visited.add(listener);
           
            for (T
i : newlisteners) {
                if (ispre(type,
i, listener)) {
                    visit(newlisteners, type, visited, ordering, i);
                }
            }
           ordering.add(listener);
        }
    }
   
    //推断观察者l1
是否在 l2 之前(每一个观察者实现了IListener接口)
    private boolean ispre(U
type, T l1, T l2) {
        return (l2.isCallbackOrderingPrereq(type,
l1.getName()) ||
                l1.isCallbackOrderingPostreq(type, l2.getName()));
    }
   
    //订阅type消息。
    public void addListener(U
type, T listener) {
        List<T> newlisteners = new ArrayList<T>();
        if (listeners != null)
            newlisteners.addAll( listeners );

        newlisteners.add(listener);
        //
Find nodes without outgoing edges
        List<T> terminals = new ArrayList<T>();
        for (T
i : newlisteners) {
            boolean isterm
true;
            for (T
j : newlisteners) {
                if (ispre(type,
i, j)) {
                    isterm = false ;
                    break ;
                }
            }
            if (isterm)
{
                terminals.add(i); //维护终节点集合
            }
        }
       
        if (terminals.size()
== 0) {
            logger .error("No
listener dependency solution: " +
                        "No
listeners without incoming dependencies");
            listeners =
newlisteners;
            return ;
        }
       
        //接下来得到有序的listeners;
        //
visit depth-first traversing in the opposite order from
        //
the dependencies.  Note we will not generally detect cycles
        HashSet<T> visited = new HashSet<T>();
        List<T> ordering = new ArrayList <T>();
        for (T
term : terminals) {
            visit(newlisteners, type, visited, ordering, term);
        }
        listeners =
ordering;
    }

    //观察者退出。为何不直接remove??
    public void removeListener(T
listener) {
        if (listeners != null)
{
            List<T> newlisteners = new ArrayList<T>();
            newlisteners.addAll( listeners );
            newlisteners.remove(listener);
            listeners =
newlisteners;
        }
    }
   
    //清除全部listeners;
    public void clearListeners()
{
        listeners = new ArrayList<T>();
    }
   
    //
    public List<T>
getOrderedListeners() {
        return listeners ;
    }
}


数据结构关联图:



















Floodlight中 处理packetin消息的顺序(2)的更多相关文章

  1. Floodlight中 处理packetin消息的顺序(1)

    当Controller和SW建立连接之后,就能够处理来自SW的各种OF msg.当接收到 packetin 消息之后,会将其分发给各个监听了这个OFMessage的listeners,所以假设我们要设 ...

  2. Floodlight 中创建消息对象的方法

            在 floodlight 中创建各种openflow message 和 action 等採用的是简单工厂方式.BasicFactory类(实现OFMessageFactory接口.) ...

  3. UML中的图的出现顺序

    上接:UML从需求到设计--用例 从开始接触UML到现在对UML逐渐有了更深入的了解.刚开始,对于UML总是感觉UML就是图.一提起UML 就想着这个是画图的东西. 具体这些图都是干什么的.为什么会有 ...

  4. WM_QUIT,WM_CLOSE,WM_DESTROY 消息出现顺序及调用方式

    http://bbs.ednchina.com/BLOG_ARTICLE_3005455.HTM VC中WM_CLOSE.WM_DESTROY.WM_QUIT消息出现顺序及调用方式 wxleasyla ...

  5. rocketmq总结(消息的顺序、重复、事务、消费模式)

    rocketmq总结(消息的顺序.重复.事务.消费模式) 参考: http://www.cnblogs.com/wxd0108/p/6038543.html https://www.cnblogs.c ...

  6. 高可用保证消息绝对顺序消费的BROKER设计方案

    转自: http://www.infoq.com/cn/articles/high-availability-broker-design?utm_source=tuicool&utm_medi ...

  7. 分布式开放消息系统RocketMQ的原理与实践(消息的顺序问题、重复问题、可靠消息/事务消息)

    备注:1.如果您此前未接触过RocketMQ,请先阅读附录部分,以便了解RocketMQ的整体架构和相关术语2.文中的MQServer与Broker表示同一概念 分布式消息系统作为实现分布式系统可扩展 ...

  8. 分布式消息队列RocketMQ&Kafka -- 消息的“顺序消费”

    在说到消息中间件的时候,我们通常都会谈到一个特性:消息的顺序消费问题.这个问题看起来很简单:Producer发送消息1, 2, 3... Consumer按1, 2, 3...顺序消费. 但实际情况却 ...

  9. MQ如何解决消息的顺序性

    一.消息的顺序性 1.延迟队列:设置一个全局变量index,根据实际情况一次按照index++的逻辑一次给消息队列设置延迟时间段,可以是0.5s,甚至1s; 弊端:如果A,B,C..消息队列消费时间不 ...

随机推荐

  1. nyoj--1009--So Easy[Ⅰ](数学)

    So Easy[Ⅰ] 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 给出任意一个三角形的三个边a,b,c. 要求:求出这个三角形的外接圆半径. 输入 输入数据有多组. ...

  2. [poj 2480] Longge's problem 解题报告 (欧拉函数)

    题目链接:http://poj.org/problem?id=2480 题目大意: 题解: 我一直很欣赏数学题完美的复杂度 #include<cstring> #include<al ...

  3. 4.C语言文件操作

    总论 1.fopen r以只读方式打开文件,该文件必须存在 r+以可读写方式打开文件,文件必须存在 rb+读写打开一个二进制文件,允许读写数据,文件必须存在 rw+读写打开一个文本文件,允许读和写 w ...

  4. vue 实现 点击取消监控内容是否发生修改 若修改提示 是否需要保存

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. Bayes++ Library入门学习之熟悉UKF相关类

    UKF-SLAM是一种比较流行SLAM方案.相比EKF-SLAM,UKF利用unscented transform代替了EKF的线性化趋近,因而具有更高的精度.Bayes++库中的unsFlt.hpp ...

  6. Python的matplotlib库画图不能显示中文问题解决

    有两种解决办法: 一种是在代码里设置为能显示中文的字体,如微软雅黑(msyh.ttf)和黑体(simsun.ttc) 如下在要画图的代码前添加: import matplotlib.pyplot as ...

  7. 使用python抓取App数据

    App接口爬取数据过程使用抓包工具手机使用代理,app所有请求通过抓包工具获得接口,分析接口反编译apk获取key突破反爬限制需要的工具:夜神模拟器FiddlerPycharm实现过程首先下载夜神模拟 ...

  8. Passpoint R1

    Passpoint R1 自从 Android 6.0 支持从网络下载包含配置文件和凭据信息的特殊文件来配置 Passpoint R1(第 1 版)凭据,Android 就一直支持 Passpoint ...

  9. BZOJ 3637: Query on a tree VI LCT_维护子树信息_点权转边权_好题

    非常喜欢这道题. 点权转边权,这样每次在切断一个点的所有儿子的时候只断掉一条边即可. Code: #include <cstring> #include <cstdio> #i ...

  10. 洛谷P3332 [ZJOI2013]K大数查询 权值线段树套区间线段树_标记永久化

    Code: #include <cstdio> #include <algorithm> #include <string> #include <cstrin ...