HttpRequest* request = new (std::nothrow) HttpRequest(); request->setUrl("http://httpbin.org/post"); request->setRequestType(HttpRequest::Type::POST); std::vector<std::string> headers; headers.push_back("Content-Type: application/json; charset=utf-8"); request->setHeaders(headers); request->setResponseCallback(CC_CALLBACK_2(HttpClientTest::onHttpRequestCompleted,this)); // write the post data const char* postData = "visitor=cocos2d&TestSuite=Extensions Test/NetworkTest"; request->setRequestData(postData,strlen(postData)); if (isImmediate) { request->setTag("POST immediate test2"); HttpClient::getInstance()->sendImmediate(request); }else { request->setTag("POST test2"); HttpClient::getInstance()->send(request); } request->release();
new出来是1
send后是2,其次还有_requestQueue是一个大Vector pushBack加1 是3
void HttpClient::send(HttpRequest* request) { if (false == lazyInitThreadSemphore()) { return; } if (!request) { return; } request->retain(); _requestQueueMutex.lock(); _requestQueue.pushBack(request); _requestQueueMutex.unlock(); // Notify thread start to work _sleepCondition.notify_one(); }
网络线程处理一个个请求,在网络线程中,取出一个后,request =_requestQueue.at(0); 移除一个,再次变为2
void HttpClient::networkThread() { increaseThreadCount(); while (true) { HttpRequest *request; // step 1: send http request if the requestQueue isn't empty { std::lock_guard<std::mutex> lock(_requestQueueMutex); while (_requestQueue.empty()) { _sleepCondition.wait(_requestQueueMutex); } request = _requestQueue.at(0); _requestQueue.erase(0); } if (request == _requestSentinel) { break; } // step 2: libcurl sync access // Create a HttpResponse object,the default setting is http access Failed HttpResponse *response = new (std::nothrow) HttpResponse(request); processResponse(response,_responseMessage); // add response packet into queue _responseQueueMutex.lock(); _responseQueue.pushBack(response); _responseQueueMutex.unlock(); _schedulerMutex.lock(); if (nullptr != _scheduler) { _scheduler->performFunctionInCocosThread(CC_CALLBACK_0(HttpClient::dispatchResponseCallbacks,this)); } _schedulerMutex.unlock(); } // cleanup: if worker thread received quit signal,clean up un-completed request queue _requestQueueMutex.lock(); _requestQueue.clear(); _requestQueueMutex.unlock(); _responseQueueMutex.lock(); _responseQueue.clear(); _responseQueueMutex.unlock(); decreaseThreadCountAndMayDeleteThis(); }
内部调用curl库处理应该返回给客户端的响应
// Process Response void HttpClient::processResponse(HttpResponse* response,char* responseMessage) { auto request = response->getHttpRequest(); long responseCode = -1; int retValue = 0; // Process the request -> get response packet switch (request->getRequestType()) { case HttpRequest::Type::GET: // HTTP GET retValue = processGetTask(this,request,writeData,response->getResponseData(),&responseCode,writeHeaderData,response->getResponseHeader(),responseMessage); break; case HttpRequest::Type::POST: // HTTP POST retValue = processPostTask(this,responseMessage); break; case HttpRequest::Type::PUT: retValue = processPutTask(this,responseMessage); break; case HttpRequest::Type::DELETE: retValue = processDeleteTask(this,responseMessage); break; default: CCASSERT(true,"CCHttpClient: unknown request type,only GET and POSt are supported"); break; } // write data to HttpResponse response->setResponseCode(responseCode); if (retValue != 0) { response->setSucceed(false); response->setErrorBuffer(responseMessage); } else { response->setSucceed(true); } }
//Process Get Request static int processGetTask(HttpClient* client,HttpRequest* request,write_callback callback,void* stream,long* responseCode,write_callback headerCallback,void* headerStream,char* errorBuffer) { CURLRaii curl; bool ok = curl.init(client,callback,stream,headerCallback,headerStream,errorBuffer) && curl.setOption(CURLOPT_FOLLOWLOCATION,true) && curl.perform(responseCode); return ok ? 0 : 1; }
获取结果后,在这里调用注册的回调函数。当分发完消息后,再次release,引用基数减1,变为1
void HttpClient::dispatchResponseCallbacks() { // log("CCHttpClient::dispatchResponseCallbacks is running"); //occurs when cocos thread fires but the network thread has already quited HttpResponse* response = nullptr; _responseQueueMutex.lock(); if (!_responseQueue.empty()) { response = _responseQueue.at(0); _responseQueue.erase(0); } _responseQueueMutex.unlock(); if (response) { HttpRequest *request = response->getHttpRequest(); const ccHttpRequestCallback& callback = request->getCallback(); Ref* pTarget = request->getTarget(); SEL_HttpResponse pSelector = request->getSelector(); if (callback != nullptr) { callback(this,response); } else if (pTarget && pSelector) { (pTarget->*pSelector)(this,response); } response->release(); // do not release in other thread request->release(); } }
注意最后的,网络线程退出while循环时,调用clear函数。
void clear()
{
for( auto it =std::begin(_data); it !=std::end(_data); ++it ) {
(*it)->release();
}
_data.clear();
}
最终里面的搜游数据引用计数因为变为0,所有内存被释放。
一个有意思的地方是:
if (request == _requestSentinel) { break; }
退出while循环的条件是这个
void HttpClient::decreaseThreadCountAndMayDeleteThis() { bool needDeleteThis = false; _threadCountMutex.lock(); --_threadCount; if (0 == _threadCount) { needDeleteThis = true; } _threadCountMutex.unlock(); if (needDeleteThis) { delete this; } }
_requestSentinel(new HttpRequest())
void HttpClient::destroyInstance() { if (nullptr == _httpClient) { CCLOG("HttpClient singleton is nullptr"); return; } CCLOG("HttpClient::destroyInstance begin"); auto thiz = _httpClient; _httpClient = nullptr; thiz->_scheduler->unscheduleAllForTarget(thiz); thiz->_schedulerMutex.lock(); thiz->_scheduler = nullptr; thiz->_schedulerMutex.unlock(); thiz->_requestQueueMutex.lock(); thiz->_requestQueue.pushBack(thiz->_requestSentinel); thiz->_requestQueueMutex.unlock(); thiz->_sleepCondition.notify_one(); thiz->decreaseThreadCountAndMayDeleteThis(); CCLOG("HttpClient::destroyInstance() finished!"); }这样,当消除单利的时候,将卫梢放进去,这样当检测出来是卫梢时,就退出网络线程。