2.live555源碼分析----服務端doEventLoop()函數分析


    上一篇博客說道,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發生事件時所需要調用的函數。

 

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM