下面貼出安卓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()返回滿足條件的套接口的數目。