三 消息循環(huán)
看服端的主體:live555MediaServer.cpp中的main()函數(shù),可見其創(chuàng)建一個RTSPServer類實例后,即進入一個函數(shù)env->taskScheduler().doEventLoop()中,看名字很明顯是一個消息循壞,執(zhí)行到里面后不停地轉圈,生名不息,轉圈不止。那么在這個人生的圈圈中如何實現(xiàn)RTSP服務和RTP傳輸呢?別想那么遠了,還是先看這個圈圈中實現(xiàn)了什么功能吧。
[cpp] view plain copyvoid BasicTaskScheduler0::doEventLoop(char* watchVariable) { // Repeatedly loop, handling readble sockets and timed events: while (1) { if (watchVariable != NULL && *watchVariable != 0) break; SingleStep(); } } BasicTaskScheduler0從TaskScheduler派生,所以還是一個任務調度對象,所以依然說明任務調度對象是整個程序的發(fā)動機。循環(huán)中每次走一步:SingleStep()。這走一步中都做些什么呢?
總結為以下四步:
1為所有需要操作的socket執(zhí)行select。
2找出第一個應執(zhí)行的socket任務(handler)并執(zhí)行之。
3找到第一個應響應的事件,并執(zhí)行之。
4找到第一個應執(zhí)行的延遲任務并執(zhí)行之。
可見,每一步中只執(zhí)行三個任務隊列中的一項。下面詳細分析函數(shù)SingleStep():
[cpp] view plain copy//循壞中主要執(zhí)行的函數(shù) 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 //計算select socket們時的超時時間。 DelayInterval const& timeToDelay = fDelayQueue.timeToNextAlarm(); struct timeval tv_timeToDelay; tv_timeToDelay.tv_sec = timeToDelay.seconds(); tv_timeToDelay.tv_usec = timeToDelay.useconds(); // Very large "tv_sec" values cause select() to fail. // Don't make it any larger than 1 million seconds (11.5 days) const long MAX_TV_SEC = MILLION; if (tv_timeToDelay.tv_sec > MAX_TV_SEC) { tv_timeToDelay.tv_sec = MAX_TV_SEC; } // Also check our "maxDelayTime" parameter (if it's > 0): if (maxDelayTime > 0 && (tv_timeToDelay.tv_sec > (long) maxDelayTime / MILLION || (tv_timeToDelay.tv_sec == (long) maxDelayTime / MILLION && tv_timeToDelay.tv_usec > (long) maxDelayTime % MILLION))) { tv_timeToDelay.tv_sec = maxDelayTime / MILLION; tv_timeToDelay.tv_usec = maxDelayTime % MILLION; } //先執(zhí)行socket的select操作,以確定哪些socket任務(handler)需要執(zhí)行。 int selectResult = select(fMaxNumSockets, &readSet, &writeSet,&exceptionSet, &tv_timeToDelay); if (selectResult < 0) { //#if defined(__WIN32__) || defined(_WIN32) int err = WSAGetLastError(); // For some unknown reason, select() in Windoze sometimes fails with WSAEINVAL if // it was called with no entries set in "readSet". If this happens, ignore it: if (err == WSAEINVAL && readSet.fd_count == 0) { err = EINTR; // To stop this from happening again, create a dummy socket: int dummySocketNum = socket(AF_INET, SOCK_DGRAM, 0); FD_SET((unsigned) dummySocketNum, &fReadSet); } if (err != EINTR) { //#else // if (errno != EINTR && errno != EAGAIN) { //#endif // Unexpected error - treat this as fatal: //#if !defined(_WIN32_WCE) // perror("BasicTaskScheduler::SingleStep(): select() fails"); //#endif internalError(); } } // Call the handler function for one readable socket: HandlerIterator iter(*fHandlers); HandlerDescriptor* handler; // To ensure forward新聞熱點
疑難解答