Live555源代码,有一个很复杂的设计架构,反正对于我一个写应用的人来说,对于解耦之类的做的很差,简直无法理解。不愿意使用多线程,接收cline和解析数据,放到一起。这种设计思路,反正我这个写APP的人,无法理解。这里还是稍微整理下。
这里我们首先了解下一个类:
BasicUsageEnvironment
这个类,其实就类似于一个静态变量,可以在任何地方调用,里面保存了几个很关键的变量,和方法,也就是可以打打印log的地方,和一个最关键的变量—-·TaskScheduler& fScheduler;
。TaskScheduler,主要用一个循环,实现了多任务的处理业务。
这是实现了整个工程任务调度的核心部分,里面处理两个任务,
最关键的一个函数,就是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();
}
这里主要是实现了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执行是在接受部分已经完成。其他的相应部分这里没有详细介绍,这里我们都是实现了初始化的部分。
这部分是相当复杂的东西,这里不是一对一的关系,主要流程是: