ARTSPConnection::postReceiveReponseEvent啓動發送請求循環

  下面貼出安卓N版本ARTSPConnection是如何啓動向服務端發送請求,接收服務端的響應這樣一個循環的:
  

==>
void ARTSPConnection::postReceiveReponseEvent() {
    //mReceiveResponseEventPending條件變量一旦postReceiveReponseEvent被調用就設置爲true,知道整個循環調用達到末端該mReceiveResponseEventPending纔會被設置爲false,這樣保證一次只存在一個這樣的循環處理
    if (mReceiveResponseEventPending) {
        return;
    }

    //新建一個消息msg,消息名爲kWhatReceiveResponse,消息的處理者爲this,也即ARTSPConnection
    //則該消息的處理髮生在ARTSPConnection::onMessageReceived的case kWhatReceiveResponse處理分支
    sp<AMessage> msg = new AMessage(kWhatReceiveResponse, this);
    msg->post();

    //將mReceiveResponseEventPending變量設置爲true,表示當前這樣的一個循環正在進行中,不能再產生一次這樣的循環。
    mReceiveResponseEventPending = true;
}

==>
void ARTSPConnection::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatConnect:
            onConnect(msg);
            break;

        case kWhatDisconnect:
            onDisconnect(msg);
            break;

        case kWhatCompleteConnection:
            onCompleteConnection(msg);
            break;

        case kWhatSendRequest:
            onSendRequest(msg);
            break;

        case kWhatReceiveResponse:
            //調用onReceiveResponse()函數對消息名爲kWhatReceiveResponse的消息進行處理
            onReceiveResponse();
            break;

        case kWhatObserveBinaryData:
        {
            CHECK(msg->findMessage("reply", &mObserveBinaryMessage));
            break;
        }

        default:
            TRESPASS();
            break;
    }
}

==>
void ARTSPConnection::onReceiveResponse() {
    //這樣的一次循環調用接近到了末端,mReceiveResponseEventPending設置爲false,表示可以再進行一次這樣的循環調用了
    mReceiveResponseEventPending = false;

    if (mState != CONNECTED) {
        return;
    }

    //創建一個timeval類型的時間結構體變量
    struct timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = kSelectTimeoutUs;

    //創建一個套接字描述符集合rs
    //並將該套接字描述符集合內存清零
    fd_set rs;
    FD_ZERO(&rs);
    //將之前創建的套接字描述符mSocket添加到該套接字描述符集合中
    FD_SET(mSocket, &rs);

    //調用select函數檢查套接字描述符集合rs裏添加的套接字的狀態,
    //即查詢它的可讀性、可寫性及錯誤狀態信息
    //在這裏查詢可讀性傳入了 &rs,其他兩個查詢可寫性及錯誤狀態信息都是傳入的NULL
    //說明在這裏調用者只檢查套接字描述符集合rs裏套接字的可讀性
    int res = select(mSocket + 1, &rs, NULL, NULL, &tv);

    if (res == 1) {
        //剛纔只通過FD_SET(mSocket, &rs)向套接字描述符集合rs裏添加了一個我們創建的套接字描述符mSocket
        //所以select函數的返回值res爲1說明,套接字描述符mSocket描述的套接口具有可讀性
        //調用MakeSocketBlocking(mSocket, true)函數阻塞該套接口,因爲接下來需要從該套接口獲取從服務端迴應的消息
        MakeSocketBlocking(mSocket, true);

        //真正的從套接口獲取服務端迴應的消息是在receiveRTSPReponse函數裏完成
        //後續文章爲大家介紹receiveRTSPReponse函數
        bool success = receiveRTSPReponse();

        //成功從該套接口獲取到服務端迴應的消息後調用MakeSocketBlocking(mSocket, false)函數將該套接口設置爲非阻塞狀態
        MakeSocketBlocking(mSocket, false);

        if (!success) {
            // Something horrible, irreparable has happened.
            flushPendingRequests();
            return;
        }
    }

    //調用postReceiveReponseEvent()函數再次開啓這樣一次處理,
    //如此就形成了一個循環
    postReceiveReponseEvent();
}

  小結:該循環的建立流程是:postReceiveReponseEvent ==> onReceiveResponse ==> postReceiveReponseEvent。這是一個設計技巧,是循環處理某些事務的機制,機制的原理就是形成一個循環調用圈。
  select函數的百科介紹:select(),確定一個或多個套接口的狀態,本函數用於確定一個或多個套接口的狀態,對每一個套接口,調用者可查詢它的可讀性、可寫性及錯誤狀態信息,用fd_set結構來表示一組等待檢查的套接口,在調用返回時,這個結構存有滿足一定條件的套接口組的子集,並且select()返回滿足條件的套接口的數目。
  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章