加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

cocos2dx HttpRequest引用计数理解

发布时间:2020-12-14 17:21:15 所属栏目:百科 来源:网络整理
导读: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,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);
	}
}


调用curl库,等待获取结果
//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!");
}
这样,当消除单利的时候,将卫梢放进去,这样当检测出来是卫梢时,就退出网络线程。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读