Live555源码阅读笔记(三):BasicUsageEnvironment 目录详解-BasicTaskScheduler、DelayQueue、HandlerSet

简介: Live555源码阅读笔记(三):BasicUsageEnvironment 目录详解-BasicTaskScheduler、DelayQueue、HandlerSet

一、BasicUsageEnvironment 目录介绍

2018122814580746.png

BasicUsageEnvironment 目录总共有12个源码文件,定义了“UsageEnvironment”类的一个具体实现(即子类),用于输出错误/警告信息;也定义了"TaskScheduler"的具体实现(子类),用于任务调度;还有哈希表的具体实现。

注意:“UsageEnvironment”类和"TaskScheduler"类是定义在 UsageEnvironment 目录的,需要了解更仔细的可以看上一篇文章(UsageEnvironment 目录详解)。


二、阅读代码

这个目录代码也简单,实现了 UsageEnvironment 类的两个子类 BasicUsageEnvironment0 类和BasicUsageEnvironment 类;实现了 TaskScheduler 类的两个子类 BasicTaskScheduler0 类和 BasicTaskScheduler 类;实现了 HashTable 类的子类 BasicHashTable;还有其他的关于延时队列的和时间、描述符队列的类,下面逐个看一下,目的是看完之后对代码结构以及这几个类有个基本的认识,再结合代码,更好地理解。

BasicUsageEnvironment 、BasicTaskScheduler、BasicHashTable的继承图:

2018122814580746.png

1、BasicUsageEnvironment0 类

由继承顺序,我们先看 BasicUsageEnvironment0 类的源码,BasicUsageEnvironment0 类的父类是 UsageEnvironment 类,由于 BasicUsageEnvironment0 类没有实现父类的所有纯虚函数,所以BasicUsageEnvironment0 类也是一个抽象类,不能直接实例化。

virtual MsgString getResultMsg() const;
virtual void setResultMsg(MsgString msg);
virtual void setResultMsg(MsgString msg1,MsgString msg2);
virtual void setResultMsg(MsgString msg1,MsgString msg2,MsgString msg3);
virtual void setResultErrMsg(MsgString msg, int err = 0);
virtual void appendToResultMsg(MsgString msg);
virtual void reportBackgroundError();

2、BasicUsageEnvironment 类

BasicUsageEnvironment 类的父类是 BasicUsageEnvironment0 类,它实现了 BasicUsageEnvironment0 类没实现的其他纯虚函数,并且没有声明新的纯虚函数,所以这个类不是抽象类,由于其构造函数 BasicUsageEnvironment 是 protected 属性的,所以这个类不能直接实例化,只能通过类内部定义的 createNew 函数来获取到指向 BasicUsageEnvironment 的指针,再通过指针使用该类。

// new 一个BasicUsageEnvironment对象,并将指针作为返回值
static BasicUsageEnvironment* createNew(TaskScheduler& taskScheduler);

下面是重写 UsageEnvironment 类跟 “重载<<运算符” 相关的函数,它的实现是直接将输入参数通过fprintf 函数打印到 stderr(标准错误文件描述符),直接看代码即可。

UsageEnvironment& BasicUsageEnvironment::operator<<(char const* str) {
  if (str == NULL) str = "(NULL)"; // sanity check
  fprintf(stderr, "%s", str); return *this;
}
UsageEnvironment& BasicUsageEnvironment::operator<<(int i) {
  fprintf(stderr, "%d", i); return *this;
}
UsageEnvironment& BasicUsageEnvironment::operator<<(unsigned u) {
  fprintf(stderr, "%u", u); return *this;
}
UsageEnvironment& BasicUsageEnvironment::operator<<(double d) {
  fprintf(stderr, "%f", d); return *this;
}
UsageEnvironment& BasicUsageEnvironment::operator<<(void* p) {
  fprintf(stderr, "%p", p); return *this;
}

3、BasicTaskScheduler0 类

BasicTaskScheduler0 类的父类是 TaskScheduler 类,由于 BasicTaskScheduler0 类仍存在纯虚函数,所以它也是一个抽象类,不能直接实例化。

3.1、BasicTaskScheduler0 类的属性

fDelayQueue  变量,延时队列,用于实现延时操作;
fHandlers 变量,处理函数(处理程序)的集合,用于实现后台读取;
fLastHandledSocketNum 变量,上次处理的描述符;
fTriggersAwaitingHandling 变量,按位操作,记录了“等待处理”的触发器id;
fLastUsedTriggerMask 变量,按位操作,记录了上次使用的触发器id;
fTriggeredEventHandlers 变量,与触发器id对应的 函数指针数组;
fTriggeredEventClientDatas 变量,传给函数的组成的数组;
fLastUsedTriggerNum 变量,记录已使用的触发器数量。

3.2、BasicTaskScheduler0 类的方法

类的开头声明了一个纯虚函数:

 virtual void SingleStep(unsigned maxDelayTime = 0) = 0;

接着,重写了父类 TaskScheduler 关于 任务调度事件触发 相关的函数,实现过程使用到DelayInterval、AlarmHandler、DelayQueueEntry等类,这些类在后面几个小节有介绍:

//做一些初始化变量的工作,new 了一个 HandlerSet 
BasicTaskScheduler0();
// new 一个定时处理对象(AlarmHandler),并添加到延时队列
virtual TaskToken scheduleDelayedTask(int64_t microseconds,TaskFunc* proc,void* clientData);
// 根据令牌从延时队列里删除一个任务
virtual void unscheduleDelayedTask(TaskToken& prevTask);
// 一直循环调用 SingleStep 处理
virtual void doEventLoop(char volatile* watchVariable);
// 把 eventHandlerProc 注册成一个事件触发器,并返回触发器id,最多可以创建 32 个
virtual EventTriggerId createEventTrigger(TaskFunc* eventHandlerProc);
// 根据事件触发器id,删除事件触发器
virtual void deleteEventTrigger(EventTriggerId eventTriggerId);
// 触发指定 id 的事件
virtual void triggerEvent(EventTriggerId eventTriggerId, void* clientData = NULL);

4、BasicTaskScheduler 类

BasicTaskScheduler 类的父类是 BasicTaskScheduler0 类,它重写了 BasicTaskScheduler0 类和 TaskScheduler 类的所有纯虚函数,但其构造函数 BasicTaskScheduler 是 protected 属性的,所以这个类不能直接实例化,只能通过类内部定义的 createNew 函数来获取到指向 BasicTaskScheduler 的指针,再通过指针使用该类。

4.1、BasicTaskScheduler 类的属性

fMaxSchedulerGranularity 变量,最大调度器粒度,表示在事件循环返回前,在select中等待的最长时间,默认是 10ms;
fMaxNumSockets变量,最大的套接字描述符,用于 select 函数
fReadSet 变量,描述符集-读取;
fWriteSet 变量,描述符集-写入;
fExceptionSet 变量,描述符集-异常。

4.2、BasicTaskScheduler 类的方法

public:
// new 一个 BasicTaskScheduler并返回该对象指针
static BasicTaskScheduler* createNew(unsigned maxSchedulerGranularity = 10000/*microseconds*/);
protected:
//构造函数,初始化并调用一次 schedulerTickTask。只在 createNew 函数会被调用
BasicTaskScheduler(unsigned maxSchedulerGranularity);
// 将 clientData 转为 BasicTaskScheduler,再调用 schedulerTickTask()
static void schedulerTickTask(void* clientData);
// 调用 scheduleDelayedTask 创建一个延时任务;
// scheduleDelayedTask的第二个参数是 TaskFunc 类型的,
// 所以第二个参数传的应该是“static void schedulerTickTask(void* clientData)”
void schedulerTickTask();
// 1.调用 select 等待一个时间 tv_timeToDelay
// 2.为一个可读套接字调用处理函数(从上次处理的套接字开始,在描述符队列往后找,找不到再从头找)
// 3.处理任何新触发的事件
virtual void SingleStep(unsigned maxDelayTime);
// 将一个处理函数添加到后台处理(添加到处理函数队列)
virtual void setBackgroundHandling(int socketNum, int conditionSet, BackgroundHandlerProc* handlerProc, void* clientData);
// 更改处理函数的描述符
virtual void moveSocketHandling(int oldSocketNum, int newSocketNum);

5、Timeval类、DelayInterval类、_EventTime类

这几个类都是和时间相关的且比较简单,放在一起说明。

Timeval 类可以是绝对时间,也可以是时间间隔,是对系统定义的结构体 struct timeval(定义在<sys/time.h>) 的一个扩展。Timeval 类主要实现了8个运算符重载函数(>=, <=, ==, !=, >, <, +=, -=),方便使用。其构造函数是 protected 的,故不能直接实例化对象。

DelayInterval 类继承自 Timeval 类,延时间隔,对 Timeval 类进一步封装。

_EventTime 类继承自 Timeval 类,事件的绝对时间。

2018122814580746.png

6、DelayQueueEntry类、DelayQueue类、AlarmHandler类

DelayQueueEntry 是一个抽象基类,延时队列入口,其作用是实现延时队列(链表)的一个节点,包含了指向自身的两个指针和数据(fDeltaTimeRemaining)。声明了一个友元类,可以用来访问自身的私有数据。

friend class DelayQueue;
属性:
        静态变量 tokenCounter,用来计算令牌总个数
        fToken 变量,实例化时返回 tokenCounter 的值;
        fDeltaTimeRemaining 变量,保存剩余时间;
        fNext 和 fPrev 变量,作为双向队列的节点指针;
方法:
        handleTimeout 函数,用来处理超时的情况,超时就 delete 当前对象指针;
        DelayQueueEntry 函数,初始化剩余时间,令牌总个数加一。

DelayQueue 继承自 DelayQueueEntry 类,延时队列,是对DelayQueueEntry 的扩展,实现了节点的添加、更新、删除。因为 DelayQueueEntry  声明了DelayQueue 为其友元类,所以DelayQueue 类可以访问到 DelayQueueEntry  的私有数据。

属性:
        fLastSyncTime 变量,记录上次同步时间;
方法:
        DelayQueue 函数,初始化队列,更新同步时间为现在;
        ~DelayQueue 函数,清空队列,从队列里删除每一个DelayQueueEntry;
        addEntry 函数,同步并添加一个 entry 到队列里​​​​​;​
        updateEntry 函数,更新队列里的 entry 的剩余时间。
        removeEntry 函数,从队列里删除一个 entry ,但没有删除该对象的指针。
        timeToNextAlarm 函数,获取下一个 entry 的剩余时间。
        handleAlarm 函数,处理剩余时间,把剩余时间为0的从队列里彻底删除。
        findEntryByToken 函数,从队列里查找指定的 entry。
        synchronize 函数,计算上次同步到现在的时间,更新"到时间"的节点

AlarmHandler 是 DelayQueueEntry 的子类,用于实现定时处理。

属性:
        fProc 变量,函数指针,指向 “到达时间时要调用” 的函数。
        fClientData 变量,传给定时函数的数据。
方法:
        handleTimeout 函数,调用定时处理函数,然后 delete 对象指针。

7、HandlerDescriptor类、HandlerSet类、HandlerIterator类

HandlerDescriptor 类是处理描述符的,记录了与描述符相关的数据(套接字号、函数指针、传给函数的数据),也定义了两个指向自身的执行,在双向链表中可以作为一个节点(包含了数据、指向自身的指针)。同时它声明了两个友元类,可以用来访问自身的私有数据:

friend class HandlerSet;
friend class HandlerIterator;
属性:
        socketNum 变量,套接字描述符;
        conditionSet 变量,条件的集合;
        handlerProc 变量,处理函数的 函数指针;
        clientData 变量,传给处理函数的数据;
        fNextHandler 变量,指向下一个节点的指针;
        fPrevHandler 变量,指向上一个节点的指针。
方法:
        HandlerDescriptor 函数,将此描述符添加到一个双向链表:
        ~HandlerDescriptor 函数,从双向链表中删除此描述符;

HandlerSet 类是处理程序(处理函数)的集合。定义了一个 HandlerDescriptor 类头节点,用双向链表来存储描述符数据,实现了描述符的添加、删除、查找等功能。同时它声明了一个友元类,可以用来访问自身的私有数据:

friend class HandlerIterator;
属性:
        fHandlers 变量,“处理程序”的描述符;
方法:
        HandlerSet 函数,初始化 fHandlers 变量,创建了一个双向链表:
        ~HandlerSet 函数,删除每个“处理程序”描述符;
        assignHandler 函数,从链表找套接字描述符,找不到就new一个并添加到链表;
        clearHandler 函数,从链表删除 socketNum 指定的套接字;
        moveHandler 函数,将旧的套接字号改为新的;
        lookupHandler 函数,从链表中寻找套接字描述符;

HandlerIterator 类是处理程序(处理函数)链表的迭代器,主要实现指针在链表里的偏移。

属性:
        fOurSet 变量,“处理程序”的集合;
        fNextPtr 变量,指向链表下个节点的指针;
方法:
        HandlerIterator 函数,初始化 fOurSet 变量,创建了一个双向链表:
        reset 函数,使指针重新偏移到链表的第一个节点;
        next 函数,使链表向下偏移一个节点,并返回该节点。

8、BasicHashTable 类

BasicHashTable 类继承自 HashTable,用于实现哈希表,在当前这个目录暂时没使用到,先不看了,等后续看到使用地方再回来补充。

总结:

UsageEnvironment 目录的源码虽然不多,但定义了好十几个类,其中比较重要的类是 BasicUsageEnvironment 类和 BasicTaskScheduler 类,其他类是在实现这两个类的过程中引申出来的,像 延时队列相关的类 和 处理函数队列相关的类 。看文章过程中可以结合代码一起看会更好理解,还有不要想着通过一篇文章就完全理解整个目录的代码了,有些类在这个目录里还没使用到,可以先知道这个类是干嘛的,等待看后面代码用到时再回来细看。这个这个目录的代码,可以知道 Live555 只有一个线程在运行,不断调用 SingleStep 函数来处理;也知道了这个目录分了几小块来实现的。

目录
相关文章
|
视频直播
视频直播源码技术知识分享:连麦功能(一)
我们开发视频直播平台就要去了解视频直播开发相关功能知识,这对我们开发平台有着重要的作用,连麦技术就是视频直播源码重要的技术功能之一,每一个功能技术都有自己的用武之地
视频直播源码技术知识分享:连麦功能(一)
|
视频直播
详解!视频直播源码平台搭建开发:录制功能
视频直播源码平台的录制功能能够为用户提供更多方便、灵活性,同时也增加了直播内容的传播和价值,这也使录制功能成为布谷科技视频直播源码平台的必备功能之一。
详解!视频直播源码平台搭建开发:录制功能
|
视频直播 定位技术 UED
海外视频直播源码技术视频直播间的搭建
大家听到这里是不是感觉这个源码平台非常的熟悉,没错,这个源码平台就海外视频直播源码平台,而我说的这个房间就是视频直播间,主持人就是视频直播间内的主播,今天我就为大家分享海外视频直播源码技术视频直播间的搭建。
海外视频直播源码技术视频直播间的搭建
|
域名解析 网络协议 安全
Live555源码阅读笔记(四):groupsock 目录详解
Live555源码阅读笔记(四):groupsock 目录详解
349 0
Live555源码阅读笔记(四):groupsock 目录详解
|
调度 C++
Live555源码阅读笔记(二):UsageEnvironment 目录详解
Live555源码阅读笔记(二):UsageEnvironment 目录详解
157 0
Live555源码阅读笔记(二):UsageEnvironment 目录详解
|
编解码 数据建模 Unix
Live555源码阅读笔记(一):源码介绍文档 及 源码目录结构
Live555源码阅读笔记(一):源码介绍文档 及 源码目录结构
412 0
Live555源码阅读笔记(一):源码介绍文档 及 源码目录结构
|
视频直播
新人主播如何赚钱,3点告诉你视频直播源码的变现方式
全民直播的时代已经到来抓住,绝大多数人是发现了直播市场的红利期,想要分一杯羹,作为新人主播如何通过视频直播源码的功能来赚钱,首先要了解市场需求,明确自己的优势,凸显自己的竞争力。
新人主播如何赚钱,3点告诉你视频直播源码的变现方式
|
存储 缓存 NoSQL
开发视频直播系统,视频直播系统源码是核心技术
了解视频直播行业的朋友应该清楚,对于开发视频直播系统而言,视频直播系统源码是真正的核心技术
开发视频直播系统,视频直播系统源码是核心技术
|
搜索推荐 视频直播
视频直播源码提高用户满意度必须要具有的特性
目前直播app应用开发市场已进入快速发展时期,不仅越来越多的直播app应用陆续投放到应用市场中,同时用户对于手机直播app应用软件的要求也越来越高。随着年轻用户群体的个性化需求提升,如何提高用户满意度,便成为了视频直播源码的开发最为关键的问题之一。  
视频直播源码提高用户满意度必须要具有的特性
|
视频直播
直播系统的顶梁柱:视频直播源码中的礼物功能
我们了解的直播系统功能是十分的实用且丰富的,一般来说,视频直播源码自带的功能有:直播功能、私信功能、邀请奖励、财务管理功能、短视频功能、直播PK功能、多种礼物功能、分享功能、拉黑功能、带货商城功能、家族功能、标签功能、评论功能等等实质性的功能,今天就针对礼物功能来做一下详细的介绍。
直播系统的顶梁柱:视频直播源码中的礼物功能