下面贴出安卓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()返回满足条件的套接口的数目。