HttpRequest* request = new (std::nothrow) HttpRequest(); request-setUrl("http://httpbin.org/post"); request-setRequestType(HttpRequest::Type::POST); std::vectorstd::string headers; headers.push_back("Content-Type: application/json; charset=
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, request,
writeData,
response->getResponseData(),
&responseCode,
writeHeaderData,
response->getResponseHeader(),
responseMessage);
break;
case HttpRequest::Type::PUT:
retValue = processPutTask(this, request,
writeData,
response->getResponseData(),
&responseCode,
writeHeaderData,
response->getResponseHeader(),
responseMessage);
break;
case HttpRequest::Type::DELETE:
retValue = processDeleteTask(this, request,
writeData,
response->getResponseData(),
&responseCode,
writeHeaderData,
response->getResponseHeader(),
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, request, 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!");
} 这样,当消除单利的时候,将卫梢放进去,这样当检测出来是卫梢时,就退出网络线程。
