2.live555源码分析----服务端doEventLoop()函数分析

来源:互联网 发布:linux关闭selinux命令 编辑:程序博客网 时间:2024/05/16 18:32

上一篇博客说道,live555服务端main函数做的最后一件事就是调用如下代码陷入死循环:

env->taskScheduler().doEventLoop(); // does not return

   那么这个doEventLoop是什么样的呢?如下:

复制代码
void BasicTaskScheduler0::doEventLoop(char* watchVariable) {  // Repeatedly loop, handling readble sockets and timed events:  while (1) {    if (watchVariable != NULL && *watchVariable != 0) break;    SingleStep();  }}
复制代码

   就是不停地调用SingleStep()这个函数,SingleStep函数中代码比较多,我下面仅截取关键代码,首先是使用selet陷入阻塞,等待事件发生:

int selectResult = select(fMaxNumSockets, &readSet, &writeSet, &exceptionSet, &tv_timeToDelay);

   返回值后之后会对所有的socket进行遍历,找到是哪个socket发生了事件:

复制代码
while ((handler = iter.next()) != NULL) {    int sock = handler->socketNum; // alias    int resultConditionSet = 0;    if (FD_ISSET(sock, &readSet) && FD_ISSET(sock, &fReadSet)/*sanity check*/) resultConditionSet |= SOCKET_READABLE;    if (FD_ISSET(sock, &writeSet) && FD_ISSET(sock, &fWriteSet)/*sanity check*/) resultConditionSet |= SOCKET_WRITABLE;    if (FD_ISSET(sock, &exceptionSet) && FD_ISSET(sock, &fExceptionSet)/*sanity check*/) resultConditionSet |= SOCKET_EXCEPTION;    if ((resultConditionSet&handler->conditionSet) != 0 && handler->handlerProc != NULL) {      fLastHandledSocketNum = sock;          // Note: we set "fLastHandledSocketNum" before calling the handler,          // in case the handler calls "doEventLoop()" reentrantly.      (*handler->handlerProc)(handler->clientData, resultConditionSet);      break;    }  }  if (handler == NULL && fLastHandledSocketNum >= 0) {    // We didn't call a handler, but we didn't get to check all of them,    // so try again from the beginning:    iter.reset();    while ((handler = iter.next()) != NULL) {      int sock = handler->socketNum; // alias      int resultConditionSet = 0;      if (FD_ISSET(sock, &readSet) && FD_ISSET(sock, &fReadSet)/*sanity check*/) resultConditionSet |= SOCKET_READABLE;      if (FD_ISSET(sock, &writeSet) && FD_ISSET(sock, &fWriteSet)/*sanity check*/) resultConditionSet |= SOCKET_WRITABLE;      if (FD_ISSET(sock, &exceptionSet) && FD_ISSET(sock, &fExceptionSet)/*sanity check*/) resultConditionSet |= SOCKET_EXCEPTION;      if ((resultConditionSet&handler->conditionSet) != 0 && handler->handlerProc != NULL) {    fLastHandledSocketNum = sock;        // Note: we set "fLastHandledSocketNum" before calling the handler,            // in case the handler calls "doEventLoop()" reentrantly.    (*handler->handlerProc)(handler->clientData, resultConditionSet);    break;      }    }    if (handler == NULL) fLastHandledSocketNum = -1;//because we didn't call a handler  }
复制代码

    当找到相应的的socket的时候,调用的是(*handler->handlerProc)这个函数,这个函数是什么呢?在上一篇博客里讲过,其实这个函数就是我们用turnOnBackgroundReadHandling()和相应socket绑定的函数,那么相对于一个server socket,绑定的就是incomingConnectionHandlerRTSP,主要功能是接受连接,创建新会话。如果是一个处理单个客户端的socket,那它绑定的就是incomingRequestHandler(),也就是负责从socket里读出数据,然后使用函数handleRequstBytes()对数据进行处理。

  handler类型是HandlerDescriptor,这个类的定义是:

 

复制代码
class HandlerDescriptor {  HandlerDescriptor(HandlerDescriptor* nextHandler);  virtual ~HandlerDescriptor();public:  int socketNum;  int conditionSet;  TaskScheduler::BackgroundHandlerProc* handlerProc;  void* clientData;private:  // Descriptors are linked together in a doubly-linked list:  friend class HandlerSet;  friend class HandlerIterator;  HandlerDescriptor* fNextHandler;  HandlerDescriptor* fPrevHandler;};
复制代码

 

    这个类存储了select监控的socket的状况和相关参数。其中:

TaskScheduler::BackgroundHandlerProc* handlerProc;
就是当这个socket发生事件时所需要调用的函数。
原创粉丝点击