您的位置:首页 > 其它

live555学习笔记3-消息循环

2017-02-16 21:12 239 查看
三 消息循环

看服端的主体:live555MediaServer.cpp中的main()函数,可见其创建一个RTSPServer类实例后,即进入一个函数env->taskScheduler().doEventLoop()中,看名字很明显是一个消息循坏,执行到里面后不停地转圈,生名不息,转圈不止。那么在这个人生的圈圈中如何实现RTSP服务和RTP传输呢?别想那么远了,还是先看这个圈圈中实现了什么功能吧。

[cpp] view
plain copy

void BasicTaskScheduler0::doEventLoop(char* watchVariable) {  

    // Repeatedly loop, handling readble sockets and timed events:  

    while (1) {  

        if (watchVariable != NULL && *watchVariable != 0)  

            break;  

        SingleStep();  

    }  

}  

BasicTaskScheduler0从TaskScheduler派生,所以还是一个任务调度对象,所以依然说明任务调度对象是整个程序的发动机。

循环中每次走一步:SingleStep()。这走一步中都做些什么呢?

总结为以下四步:

1为所有需要操作的socket执行select。

2找出第一个应执行的socket任务(handler)并执行之。

3找到第一个应响应的事件,并执行之。

4找到第一个应执行的延迟任务并执行之。

可见,每一步中只执行三个任务队列中的一项。下面详细分析函数SingleStep():

[cpp] view
plain copy

//循坏中主要执行的函数  

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;  

    }  

  

    //先执行socket的select操作,以确定哪些socket任务(handler)需要执行。  

    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 progress through the handlers, begin past the last  

    // socket number that we handled:  

    if (fLastHandledSocketNum >= 0) {  

        //找到上次执行的socket handler的下一个  

        while ((handler = iter.next()) != NULL) {  

            if (handler->socketNum == fLastHandledSocketNum)  

                break;  

        }  

        if (handler == NULL) {  

            fLastHandledSocketNum = -1;  

            iter.reset(); // start from the beginning instead  

        }  

    }  

  

    //从找到的handler开始,找一个可以执行的handler,不论其状态是可读,可写,还是出错,执行之。  

    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;  

        }  

    }  

  

    //如果寻找完了依然没有执行任何handle,则从头再找。  

    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;  

            }  

        }  

  

        //依然没有找到可执行的handler。  

        if (handler == NULL)  

            fLastHandledSocketNum = -1; //because we didn't call a handler  

    }  

  

    //响应事件  

    // Also handle any newly-triggered event  

    // (Note that we do this *after* calling a socket handler,  

    // in case the triggered event handler modifies The set of readable sockets.)  

    if (fTriggersAwaitingHandling != 0) {  

        if (fTriggersAwaitingHandling == fLastUsedTriggerMask) {  

            // Common-case optimization for a single event trigger:  

            fTriggersAwaitingHandling = 0;  

            if (fTriggeredEventHandlers[fLastUsedTriggerNum] != NULL) {  

                //执行一个事件处理函数  

                (*fTriggeredEventHandlers[fLastUsedTriggerNum])(fTriggeredEventClientDatas[fLastUsedTriggerNum]);  

            }  

        } else {  

            // Look for an event trigger that needs handling  

            // (making sure that we make forward progress through all possible triggers):  

            unsigned i = fLastUsedTriggerNum;  

            EventTriggerId mask = fLastUsedTriggerMask;  

  

            do {  

                i = (i + 1) % MAX_NUM_EVENT_TRIGGERS;  

                mask >>= 1;  

                if (mask == 0)  

                    mask = 0x80000000;  

  

                if ((fTriggersAwaitingHandling & mask) != 0) {  

                    //执行一个事件响应  

                    fTriggersAwaitingHandling &= ~mask;  

                    if (fTriggeredEventHandlers[i] != NULL) {  

                        (*fTriggeredEventHandlers[i])(fTriggeredEventClientDatas[i]);  

                    }  

  

                    fLastUsedTriggerMask = mask;  

                    fLastUsedTriggerNum = i;  

                    break;  

                }  

            } while (i != fLastUsedTriggerNum);  

        }  

    }  

  

    //执行一个最迫切的延迟任务。  

    // Also handle any delayed event that may have come due.  

    fDelayQueue.handleAlarm();  

}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: