• 7 HandlerSet 处理程序链表类——Live555源码阅读(一)基本组件类


    这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类。

    本文由乌合之众 lym瞎编,欢迎转载 my.oschina.net/oloroso

    HandlerSet 处理程序链表类

    这里使用的Set这个单词,Set是集合的意思,这里实质上是一个双向循环链表。这个类比较重要,这里会详细的介绍。
    HandlerSet类只有一个数据成员,就是HandlerDescriptor fHandlers;这是作为链表的头结点而存在的。
    HandlerSet_class_uml.png

    HandlerSet_2.png


    HandlerSet的定义,代码如下

    class HandlerSet {
    public:
    	//设置fHandlers的下一个和上一个指向fHandler自己
    	HandlerSet();
    	//逐个释放链表节点
    	virtual ~HandlerSet();
    	// 从链表中查找socketNum代表的HandlerDescriptor,如果没有找到就创建一个并加入到链表
    	void assignHandler(int socketNum, int conditionSet, TaskScheduler::BackgroundHandlerProc* handlerProc, void* clientData);
    	//从链表中查找socketNum对应的HandlerDescriptor,找到了就delete
    	void clearHandler(int socketNum);
    	// 从链表中查找oldSocketNum代表的HandlerDescriptor,找到了就将其sockerNum成员替换为newSocketNum
    	void moveHandler(int oldSocketNum, int newSocketNum);
    private:
    	// 从链表中查找socketNum代表的HandlerDescriptor,没找到返回NULL
    	HandlerDescriptor* lookupHandler(int socketNum);
    private:
    	friend class HandlerIterator;
    	HandlerDescriptor fHandlers;	//处理程序描述对象 链表头节点
    };
    

    HandlerSet的构造

    在其构造函数中,默认对头结点HandlerDescriptor fHandlers进行了初始化操作。

    HandlerSet::HandlerSet()
      : fHandlers(&fHandlers) {
      fHandlers.socketNum = -1; // shouldn't ever get looked at, but in case...
    }
    

    这里调用了HandlerDescriptor的构造,这个可以在之前的介绍中查看。这里可以看到,其将头结点的数据成员socketNum设置为了-1,之前我们说过,socketNum在链表中被用来标识节点,这里说明了其是一个特殊的存在,头结点不做为保存处理程序的节点。


    HandlerSet的析构

    析构函数就是释放链表,就是逐个释放除了头结点之外的节点。代码如下

    HandlerSet::~HandlerSet() {
      // Delete each handler descriptor:
      while (fHandlers.fNextHandler != &fHandlers) {
        delete fHandlers.fNextHandler; // changes fHandlers->fNextHandler
      }
    }
    

    lookupHandler方法

    这里先说这个方法,因为后面的几个方法都用到了它。从方法名也可以看出来,这个方法是用来查找节点的。
    这里要说以下的就是,这里面用到了迭代器。方法中创建了一个迭代器,并将自身绑定给了迭代器。前面说过迭代器构造的时候会将其fNextPtr指向链表的头结点的下一个。也就是说会从第二个节点开始查找。如果本身就只有头节点呢?因为在只有头结点的情况下,下一个节点就是头结点,其socketNum为-1,这里是没问题的。

    HandlerDescriptor* HandlerSet::lookupHandler(int socketNum) {
      HandlerDescriptor* handler;
      HandlerIterator iter(*this);
      while ((handler = iter.next()) != NULL) {
        if (handler->socketNum == socketNum) break;
      }
      return handler;
    }
    

    assignHandler(分配处理程序)方法

    通过前面的描述可知,HandlerSet类都是在操作内部的一个双向链表。但是HandlerSet是没有一个addNode方法的,这个方法就由assignHandler来做了。
    assignHandler的参数有四个,对应了一个节点对象的四个数据成员** socketNum/conditionSet/handlerProc/clientData **。前面说过socketNum成员在链表中用来标识节点,在这个成员方法中就可以看出来。这个方法会在BasicTaskScheduler的setBackgroundHandling方法中被用到。其socketNum参数应该是传一个socket套接口给它。
    assignHandler方法先是从链表中查找socketNum标识的节点是否存在,如果不存在就new一个,并设置新节点的socketNum为参数的socketNum。这样链表中就存在了一个标识为参数socketNum的节点。然后把这个节点的 处理程序指针,客户端数据地址,条件集合都更新为参数中的。

    void HandlerSet::assignHandler(int socketNum, int conditionSet, TaskScheduler::BackgroundHandlerProc* handlerProc, void* clientData) {
      // First, see if there's already a handler for this socket:
      HandlerDescriptor* handler = lookupHandler(socketNum);
      if (handler == NULL) { // No existing handler, so create a new descr:
        handler = new HandlerDescriptor(fHandlers.fNextHandler);
        handler->socketNum = socketNum;
      }
    
      handler->conditionSet = conditionSet;
      handler->handlerProc = handlerProc;
      handler->clientData = clientData;
    }
    

    clearHandler和moveHandler方法

    这两个方法比较类似,放在一起来说。
    clearHandler方法是从链表中找socketNum标识的节点,然后delete这个节点。有之前的描述可以知道,这里把找到的节点从链表中移除了。如果没有找到呢? lookupHandler会返回NULL,delete NULL,是可以的。

    void HandlerSet::clearHandler(int socketNum) {
      HandlerDescriptor* handler = lookupHandler(socketNum);
      delete handler;
    }
    

    moveHandler则是从链表中找oldSocketNum标识的节点,找到了就将其标识替换为newSocketNum。如果没有找到就声明也不做了。这里和前面说的assignHandler方法来对比下。assignHandler是找到了就替换其他的三个数据成员,这里是找到了就替换标识。

    void HandlerSet::moveHandler(int oldSocketNum, int newSocketNum) {
      HandlerDescriptor* handler = lookupHandler(oldSocketNum);
      if (handler != NULL) {
        handler->socketNum = newSocketNum;
      }
    }
    
  • 相关阅读:
    android不知不觉偷拍他人功能实现(手机关闭依然拍照)【申明:来源于网络】
    地图标绘系统V1.0测试版【申明:来源于网络】
    AngularJS资源合集[备忘]【申明:来源于网络】
    java+js实现展示本地文件夹下的所有图片demo[申明:来源于网络]
    angular源码分析 摘抄 王大鹏 博客 directive指令及系列
    jQuery学习之prop和attr的区别
    顽Shi的实践总结
    URL 中#号,? ,&的作用 (摘抄整理 链接为学习地址)
    YeoMan 与Angularjs
    an'gularjs 环境搭建之NodeJS、NPM安装配置步骤(windows版本)
  • 原文地址:https://www.cnblogs.com/oloroso/p/4596843.html
Copyright © 2020-2023  润新知