前面通过阅读代码知道了怎样推断各个模块处理某个消息的先后顺序。那么内部是怎样实现的呢?
     每当一个模块表示对一个消息感兴趣的时候,就会调用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对象是否存在
             ListenerDispatcher< OFType, IOFMessageListener>
ldd =
                 messageListeners.get(type);
             if (ldd
== null ) {
                 ldd = new ListenerDispatcher< OFType, IOFMessageListener>();
                 messageListeners.put(type, ldd);
             }
             //注冊监听type这个消息。
             ldd.addListener(type, listener);
         }
--------------ListenerDispatcher实现(维护这些观察者,有依赖关系)

public class ListenerDispatcher <U,
T 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. border:none与border:0的区别

    border:none与border:0的区别体现为两点:一是理论上的性能差异,二是浏览器兼容性的差异. 性能差异: [border:0;]把border设为“0”像素效果等于border-width ...

  2. 关于fetch

    前言: fetch是用来取代传统的XMLHttpRequest的. 它的优点很多,包括链式调用的语法.返回promise等. 什么是fetch? fetch api是基于promise的设计,它是为了 ...

  3. BZOJ 1024 SCOI2009 生日快乐 暴搜

    思路:eng...按照题意搜就好了 (一定要注意题面的n<=10--) 枚举断点...反正n<=10不怂 //By SiriusRen #include <cstdio> #i ...

  4. tomcat到底是干什么用的?用大白话讲一下

    通俗点说他是jsp网站的服务器之一,就像asp网站要用到微软的IIS服务器,php网站用apache服务器一样,因为你的jsp动态网站使用脚本语言等写的,需要有服务器来解释你的语言吧,服务器就是这个功 ...

  5. Python实现文件阅读功能(Python学习笔记)

    #!/usr/bin/python# Filename: filereader.pyimport sys def readfile(filename): '''Print a file to the ...

  6. 用 while 循环做个小游戏

    import random #可输入次数 flag = 0 #生成一个1到10之间的随机整数 res = random.randint(1,10) #判读三次输入机会 while(flag<3) ...

  7. php八大设计模式之工厂模式

    简单点来说,就是用到什么类,就去实例化对应的类.比如:php 可能连接 mysql,可能连接 sqlserver,也可能是 oracle 数据库,可以动态的去链接. 书籍<php权威编程> ...

  8. 关于 nginx 的配置的 location

    精准匹配和普通匹配:    server{            location =/index.htm{                                       ////精准匹 ...

  9. ArchLinux 设置时间同步和硬件时间同步错误 No usable clock interface found

    笔记本不知道怎么了,总是时间对不上 硬件时间也设置不了,只能时间同步了 手动时间同步 ntpdate即可,ntp服务器在这里用这两个就好了 cn.ntp.org.cn 或 edu.ntp.org.cn ...

  10. BZOJ 3626 LCA(离线+树链剖分+差分)

    显然,暴力求解的复杂度是无法承受的. 考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案.观察到,深度其实就是上面有几个已 ...