Live555源码分析之1

1. 前言

Live555源代码,有一个很复杂的设计架构,反正对于我一个写应用的人来说,对于解耦之类的做的很差,简直无法理解。不愿意使用多线程,接收cline和解析数据,放到一起。这种设计思路,反正我这个写APP的人,无法理解。这里还是稍微整理下。

2. 正文

这里我们首先了解下一个类:
BasicUsageEnvironment 这个类,其实就类似于一个静态变量,可以在任何地方调用,里面保存了几个很关键的变量,和方法,也就是可以打打印log的地方,和一个最关键的变量—-·TaskScheduler& fScheduler;。TaskScheduler,主要用一个循环,实现了多任务的处理业务。

2.2 进程关管理

这是实现了整个工程任务调度的核心部分,里面处理两个任务,

  1. 读取socket内容,作为server端,相应服务器
  2. 读取文件,进行分发

最关键的一个函数,就是SingleStep,这个就是模拟了一个cpu的流水线,一直在循环的处理一些事情,最终实现server的相应,

void BasicTaskScheduler::SingleStep(unsigned maxDelayTime) {
  fd_set readSet = fReadSet; // make a copy for this select() call
  fd_set writeSet = fWriteSet; // ditto
  fd_set exceptionSet = fExceptionSet; // ditto

    ......

//读取socket内容,
  int selectResult = select(fMaxNumSockets, &readSet, &writeSet, &exceptionSet, &tv_timeToDelay);

    ......

 //处理socker内容。
      (*handler->handlerProc)(handler->clientData, resultConditionSet);

  //这是一个处理定时业务,大部分都是处理读取文件的内容,反复定时内容,实现逻辑
  fDelayQueue.handleAlarm();
}

2.2 server的实现

这里主要是实现了Socket,然后向TaskScheduler注册回调,首先是Socket的初始化。

DynamicRTSPServer*
DynamicRTSPServer::createNew(UsageEnvironment& env, Port ourPort,
                 UserAuthenticationDatabase* authDatabase,
                 unsigned reclamationTestSeconds) {
    //初始化出现一个socket的引用,类似于文件。
  int ourSocket = setUpOurSocket(env, ourPort);

}

这里初始化完成,然后要向TaskScheduler注册回调

GenericMediaServer
::GenericMediaServer(UsageEnvironment& env, int ourSocket, Port ourPort,
             unsigned reclamationSeconds)

    ......

  env.taskScheduler().turnOnBackgroundReadHandling(fServerSocket, incomingConnectionHandler, this);
}

这里传入的incomingConnectionHandler这是有Socket的传入参数,实现的具体逻辑,

void BasicTaskScheduler
  ::setBackgroundHandling(int socketNum, int conditionSet, BackgroundHandlerProc* handlerProc, void* clientData) {

    ......
    fHandlers->assignHandler(socketNum, conditionSet, handlerProc, clientData);
    if (conditionSet&SOCKET_READABLE) FD_SET((unsigned)socketNum, &fReadSet);
    if (conditionSet&SOCKET_WRITABLE) FD_SET((unsigned)socketNum, &fWriteSet);
    if (conditionSet&SOCKET_EXCEPTION) FD_SET((unsigned)socketNum, &fExceptionSet);
}

最终回调主要是

void GenericMediaServer::incomingConnectionHandlerOnSocket(int serverSocket) {

  ......

  // Create a new object for handling this connection:
  (void)createNewClientConnection(clientSocket, clientAddr);
}


GenericMediaServer::ClientConnection
::ClientConnection(GenericMediaServer& ourServer, int clientSocket, struct sockaddr_in clientAddr)
  : fOurServer(ourServer), fOurSocket(clientSocket), fClientAddr(clientAddr) {

  envir().taskScheduler()
    .setBackgroundHandling(fOurSocket, SOCKET_READABLE|SOCKET_EXCEPTION, incomingRequestHandler, this);
}

这是实现了第一次请求的全过程,然后等待第二次连接,才开始分发数据。我们接着看第二次连接,

void RTSPServer::RTSPClientConnection::handleRequestBytes(int newBytesRead) {

......
handleCmd_DESCRIBE(urlPreSuffix, urlSuffix, (char const*)fRequestBuffer);
......

static ServerMediaSession* createNewSMS(UsageEnvironment& env,
                    char const* fileName, FILE* /*fid*/) {


    MatroskaFileServerDemux::createNew(env, fileName, onMatroskaDemuxCreation, &creationState);
    env.taskScheduler().doEventLoop(&creationState.watchVariable);
}

这里MatroskaFileServerDemux这是类似于一个server的东西,用来产生数据,真正的server的代码执行还是进程管理的工具执行。这里的代码部分的server执行是在接受部分已经完成。其他的相应部分这里没有详细介绍,这里我们都是实现了初始化的部分。

2.3 读取文件

这部分是相当复杂的东西,这里不是一对一的关系,主要流程是:

你可能感兴趣的:(c-cpp语言)