cocos2d-x学习篇之网络(http)篇

前端之家收集整理的这篇文章主要介绍了cocos2d-x学习篇之网络(http)篇前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

转自:http://blog.csdn.net/duotianshi86/article/details/10216383

这段时间接触到cocos2d-x,拜读了csdn上很多大大的文章,尤其是小满的专栏,感觉获益不少,觉得像他们那样,边学习,边总结经验,并写出来学习过程与大家分享,我觉得是一件很值得学习的事,所以也打算把自己学习的东西和经验与大家分享,有不足之处或者错误的,还希望请大家能海涵并提出来,共同讨论,共同进步。好了,废话到此。

Cocos2dx 为我们封装了在cocos2dx中http的网络框架,其文件在cocos2dx引擎包的cocos2d-2.1rc0-x-2.1.2\extensions\network文件下的 HttpClient、HttpRequest 、HttpResponse。但是真正的底层,用的还是cURL库。。。

进行一次http交互,需要涉及的有三个类,HttpRequest用来描述一个请求。HttpResponse用来描述对应请求的响应。HttpClient是一个单例模式的类,它的职责就是负责将收到的HttpRequest对象push到发送队列中,并发送一个信号量驱动工作线程工作,工作线程再将收到的数据封装成一个HttpResponse对象push接收队列,并启用调度来派送数据。具体的后面有说道。

1.首先创建一个类,继承自cocos2d-x中的任何一个类都可以(有共同父类CCObject),并实现一个SEL_CallFuncND类型成员函数,用来做收到数据后的回调函数函数原型为void fun(CCNode*,void*)。

2.当我们需要一次http交互的时候,我们需要new 一个CCHttpRequest对象,并设置url和请求方式(get还是post,本文只说一下get的原理,post区别不大,可以自己看),并将上面说函数设置为收到数据后的回调函数

3.使用CCHttpClient::getInstance()单例对象,将前一步骤的CCHttpRequest对象作为参数,调用send()方法

4.在回调函数中,将第二个参数转换成CCHttpResponse *类型,就可以通过CCHttpResponse类的方法获取返回状态和数据等能容了。

我们先来看看具体的该怎么用,以自带的HttpClientTest.cpp为例。HttpClientTest.cpp:

  1. //get请求@H_502_56@
  2. void@H_502_56@HttpClientTest::onMenuGetTestClicked(cocos2d::CCObject*sender)
  3. {
  4. //test1@H_502_56@
  5. CCHttpRequest*request=new@H_502_56@CCHttpRequest();//创建request对象,这里new出来的对象不能使用autorelease(),原因后述@H_502_56@
  6. request->setUrl("http://just-make-this-request-Failed.com"@H_502_56@);//设置url
  7. request->setRequestType(CCHttpRequest::kHttpGet);//设置请求方式@H_502_56@
  8. request->setResponseCallback(this@H_502_56@,callfuncND_selector(HttpClientTest::onHttpRequestCompleted));//这是回调对象和回调函数@H_502_56@
  9. request->setTag("GETtest1"@H_502_56@);//设置用户标识,可以通过response获取@H_502_56@
  10. CCHttpClient::getInstance()->send(request);//使用CCHttpClient共享实例来发送request@H_502_56@
  11. request->release();//调用release()@H_502_56@
  12. }
  13. //waiting@H_502_56@
  14. m_labelStatusCode->setString("waiting..."@H_502_56@);
  15. }
  16. //这里就是我们要处理接收到数据的回调函数了,sender为CCHttpClient实例指针,data为接收到的response指针@H_502_56@
  17. void@H_502_56@HttpClientTest::onHttpRequestCompleted(cocos2d::CCNode*sender,void@H_502_56@*data)
  18. CCHttpResponse*response=(CCHttpResponse*)data;
  19. if@H_502_56@(!response)
  20. return@H_502_56@;
  21. //获取对应request的字符串标识@H_502_56@
  22. if@H_502_56@(0!=strlen(response->getHttpRequest()->getTag()))
  23. CCLog("%scompleted"@H_502_56@,response->getHttpRequest()->getTag());
  24. //获取返回代码,比如200、404@H_502_56@
  25. int@H_502_56@statusCode=response->getResponseCode();
  26. char@H_502_56@statusString[64]={};
  27. sprintf(statusString,"HTTPStatusCode:%d,tag=%s"@H_502_56@,statusCode,response->getHttpRequest()->getTag());
  28. m_labelStatusCode->setString(statusString);
  29. CCLog("responsecode:%d"@H_502_56@,statusCode);
  30. if@H_502_56@(!response->isSucceed())
  31. {
  32. CCLog("responseFailed"@H_502_56@);
  33. CCLog("errorbuffer:%s"@H_502_56@,response->getErrorBuffer());//可以调用getErrorBuffer()来获取错误原因@H_502_56@
  34. return@H_502_56@;
  35. //dumpdata@H_502_56@
  36. std::vector<char@H_502_56@>*buffer=response->getResponseData();//用来获取接收到的数据@H_502_56@
  37. printf("HttpTest,dumpdata:"@H_502_56@);
  38. for@H_502_56@(unsignedint@H_502_56@i=0;i<buffer->size();i++)
  39. printf("%c"@H_502_56@,(*buffer)[i]);
  40. printf("\n"@H_502_56@);
  41. }


基本上一个http交互就是这个样子了,下面我们深入的看一下CCHttpClient是怎么工作的,先来看一张图,画的不好或者不足之处,请勿拍砖

其实就是当我们第一次CCHttpClient::getInstance()时,CCHttpClient会将自己的成员函数dispathResponseCallbacks()挂载至CCScheduler(可以理解成一个调度者,它会定时调用所有挂载至上面的函数),并将它初始设置为停止调度。在当我们第一次调用send()发送数据时,CCHttpClient会创建一个工作线程(之后再调用send()就不会创建线程了),然后再将传递过来的CCHttpRequest对象push到发送队列s_requestQueue,并发送一个信号给工作线程,驱使其工作。工作线程首先从发送队列中取得一个CCHttpRequest对象,并new 一个CCHttpResponse对象,将参数设置给cURL,cURL会在获取到数据的填充response,工作线程将填充后的response再放到接收队列s_responseQueue中去,同时,启用调度。下一次CCScheduler就会CCHttpClient::dispatchResponseCallbacks()了,在该函数中,它会调用我们在第二步中设置给request的回调函数,并将response传递过去。基本过程就是这样。下面来详解相关的源文件。HttpRequest.h,其实这个文件没什么好说的,都有注释

copy
@H_221_404@ class@H_502_56@CCHttpRequest:public@H_502_56@CCObject
  • public@H_502_56@:
  • /**请求类型枚举,可以通过setReqeustType(param)设置*/@H_502_56@
  • typedef@H_502_56@enum@H_502_56@
  • kHttpGet,
  • kHttpPost,
  • kHttpUnkown,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> }HttpRequestType;
  • /**Constructor
  • BecauseHttpRequestobjectwillbeusedbetweenUItheadandnetworkthread,
  • requestObj->autorelease()isforbiddentoavoidcrashesinCCAutoreleasePool
  • new/retain/releasestillworks,whichmeansyouneedtoreleaseitmanually
  • PleaserefertoHttpRequestTest.cpptofinditsusage
  • 这里是有注释的,因为要跨线程,所以就不能用autorelease()
  • 我们在使用HttpRequest的时候,需要自己new,然后再release下就可以了
  • 当我们把HttpRequest传递给CCHttpClient的时候,CCHttpClient已经帮我们retain了
  • 工作线程中,需要使用CCHttpRequest对象new一个CCHttpResponse,CCHttprequest会retain一次,所以工作线程也会release一次
  • 具体的后文有
  • */@H_502_56@
  • CCHttpRequest()
  • _requestType=kHttpUnkown;
  • _url.clear();
  • _requestData.clear();
  • _tag.clear();
  • _pTarget=NULL;
  • _pSelector=NULL;
  • _pUserData=NULL;
  • };
  • virtual@H_502_56@~CCHttpRequest()
  • if@H_502_56@(_pTarget)
  • _pTarget->release();
  • /**重载autorelease函数禁止调用*/@H_502_56@
  • CCObject*autorelease(void@H_502_56@)
  • CCAssert(false@H_502_56@,"HttpResponseisusedbetweennetworkthread@H_502_56@anduithread@H_502_56@\
  • therefore,autoreleaseisforbiddenhere");
  • return@H_502_56@NULL;
  • //setter/gettersforproperties@H_502_56@
  • /**设置请求类型
  • 目前支持kHttpGet和kHttpPost
  • inline@H_502_56@void@H_502_56@setRequestType(HttpRequestTypetype)
  • _requestType=type;
  • /**返回请求类型*/@H_502_56@
  • inline@H_502_56@HttpRequestTypegetRequestType()
  • return@H_502_56@_requestType;
  • };
  • /**设置请求url
  • inline@H_502_56@void@H_502_56@setUrl(const@H_502_56@char@H_502_56@*url)
  • _url=url;
  • /**获取请求url*/@H_502_56@
  • inline@H_502_56@const@H_502_56@char@H_502_56@*getUrl()
  • return@H_502_56@_url.c_str();
  • /**这个设置用于post方式的data数据
  • inline@H_502_56@void@H_502_56@setRequestData(const@H_502_56@char@H_502_56@*buffer,unsignedint@H_502_56@len)
  • _requestData.assign(buffer,buffer+len);
  • /**Gettherequestdatapointerback*/@H_502_56@
  • inline@H_502_56@char@H_502_56@*getRequestData()
  • return@H_502_56@&(_requestData.front());
  • /**Getthesizeofrequestdataback*/@H_502_56@
  • inline@H_502_56@int@H_502_56@getRequestDataSize()
  • return@H_502_56@_requestData.size();
  • /**为每个请求设置一个字符串标示,可以通过HttpResponse->getHttpRequest->getTag()获取,因为HttpResponse会将对应的HttpRequest封装在里面
  • */@H_502_56@
  • inline@H_502_56@void@H_502_56@setTag(const@H_502_56@char@H_502_56@*tag)
  • _tag=tag;
  • /**Getthestringtagbacktoidentifytherequest.
  • ThebestpracticeistouseitinyourMyClass::onMyHttpRequestCompleted(sender,HttpResponse*)callback
  • inline@H_502_56@const@H_502_56@char@H_502_56@*getTag()
  • return@H_502_56@_tag.c_str();
  • /**Optionfield.Youcanattachacustomeddataineachrequest,andgetitbackinresponsecallback.
  • Butyouneedtonew/deletethedatapointermanully
  • inline@H_502_56@void@H_502_56@setUserData(void@H_502_56@*pUserData)
  • _pUserData=pUserData;
  • /**Getthepre-settedcustomdatapointerback.
  • Don'tforgettodeleteit.HttpClient/HttpResponse/HttpRequestwilldonothingwiththispointer
  • inline@H_502_56@void@H_502_56@*getUserData()
  • return@H_502_56@_pUserData;
  • /**通过这个函数设置我们的数据处理回调函数
  • inline@H_502_56@void@H_502_56@setResponseCallback(CCObject*pTarget,SEL_CallFuncNDpSelector)
  • _pTarget=pTarget;
  • _pSelector=pSelector;
  • _pTarget->retain();
  • /**Getthetargetofcallbackselectorfuntion,mainlyusedbyCCHttpClient*/@H_502_56@
  • inline@H_502_56@CCObject*getTarget()
  • return@H_502_56@_pTarget;
  • /**Gettheselectorfunctionpointer,mainlyusedbyCCHttpClient*/@H_502_56@
  • inline@H_502_56@SEL_CallFuncNDgetSelector()
  • return@H_502_56@_pSelector;
  • /**Setanycustomheaders**/@H_502_56@
  • inline@H_502_56@void@H_502_56@setHeaders(std::vector<std::string>pHeaders)
  • _headers=pHeaders;
  • /**Getcustomheaders**/@H_502_56@
  • inline@H_502_56@std::vector<std::string>getHeaders()
  • return@H_502_56@_headers;
  • protected@H_502_56@:
  • //properties@H_502_56@
  • HttpRequestType_requestType;///请求方式@H_502_56@
  • std::string_url;///请求url@H_502_56@
  • std::vector<char@H_502_56@>_requestData;///用于POST@H_502_56@
  • std::string_tag;///用户自定义标识,可以用来在response回调中区分request@H_502_56@
  • CCObject*_pTarget;///回调对象@H_502_56@
  • SEL_CallFuncND_pSelector;///回调函数例如MyLayer::onHttpResponse(CCObject*sender,void*data)@H_502_56@
  • void@H_502_56@*_pUserData;///用户自定义数据,和_tag用法一样,只不过是用途不一样@H_502_56@
  • std::vector<std::string>_headers;///customhttpheaders@H_502_56@
  • };

  • HttpResponse.h,这个文件和HttpRequest差不多,没什么好说的
    copy
    @H_221_404@ class@H_502_56@CCHttpResponse:public@H_502_56@CCObject
  • /**Constructor,it'susedbyCCHttpClientinternal,usersdon'tneedtocreateHttpResponsemanually
  • @paramrequestthecorrespondingHttpRequestwhichleadstothisresponse
  • CCHttpResponse(CCHttpRequest*request)
  • _pHttpRequest=request;
  • if@H_502_56@(_pHttpRequest)
  • _pHttpRequest->retain();
  • _succeed=false@H_502_56@;
  • _responseData.clear();
  • _errorBuffer.clear();
  • /**Destructor,itwillbecalledinCCHttpClientinternal,
  • usersdon'tneedtodesturctHttpResponSEObjectmanully
  • virtual@H_502_56@~CCHttpResponse()
  • if@H_502_56@(_pHttpRequest)
  • _pHttpRequest->release();
  • /**Overrideautoreleasemethodtopreventdevelopersfromcallingit*/@H_502_56@
  • CCObject*autorelease(void@H_502_56@)
  • CCAssert(false@H_502_56@,"HttpResponseisusedbetweennetworkthread@H_502_56@anduithread@H_502_56@\
  • therefore,autoreleaseisforbiddenhere");
  • return@H_502_56@NULL;
  • //getters,willbecalledbyusers@H_502_56@
  • /**GetthecorrespondingHttpRequestobjectwhichleadstothisresponse
  • There'snopairedsetterforit,cozit'salreadysettedinclassconstructor
  • inline@H_502_56@CCHttpRequest*getHttpRequest()
  • return@H_502_56@_pHttpRequest;
  • /**Toseeifthehttpreqeustisreturnedsuccessfully,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> Althroughuserscanjudgeif(httpreturncode=200),wewantaneasierway
  • Ifthisgetterreturnsfalse,youcancallgetResponseCodeandgetErrorBuffertofindmoredetails
  • inline@H_502_56@bool@H_502_56@isSucceed()
  • return@H_502_56@_succeed;
  • /**Getthehttpresponserawdata*/@H_502_56@
  • inline@H_502_56@std::vector<char@H_502_56@>*getResponseData()
  • return@H_502_56@&_responseData;
  • /**GetthehttpresponseerrorCode
  • *Iknowthatyouwanttoseehttp200:)
  • inline@H_502_56@int@H_502_56@getResponseCode()
  • return@H_502_56@_responseCode;
  • /**GettherrorbufferwhichwilltellyoumoreaboutthereasonwhyhttprequestFailed
  • inline@H_502_56@const@H_502_56@char@H_502_56@*getErrorBuffer()
  • return@H_502_56@_errorBuffer.c_str();
  • //setters,willbecalledbyCCHttpClient@H_502_56@
  • //useRSShouldavoidinvokingthesemethods@H_502_56@
  • /**Setifthehttprequestisreturnedsuccessfully,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> Althroughuserscanjudgeif(httpcode==200),wewantaeasierway
  • ThissetterismainlyusedinCCHttpClient,usersmustn'tsetitdirectly
  • inline@H_502_56@void@H_502_56@setSucceed(bool@H_502_56@value)
  • _succeed=value;
  • /**Setthehttpresponserawbuffer,isusedbyCCHttpClient
  • inline@H_502_56@void@H_502_56@setResponseData(std::vector<char@H_502_56@>*data)
  • _responseData=*data;
  • /**SetthehttpresponseerrorCode
  • inline@H_502_56@void@H_502_56@setResponseCode(int@H_502_56@value)
  • _responseCode=value;
  • /**SettheerrorbufferwhichwilltellyoumorethereasonwhyhttprequestFailed
  • inline@H_502_56@void@H_502_56@setErrorBuffer(const@H_502_56@char@H_502_56@*value)
  • _errorBuffer.assign(value);
  • bool@H_502_56@initWithRequest(CCHttpRequest*request);
  • //这里要留意下,每个response中都会包含对应的request,所以能在数据处理回调函数中,获取我们在设置request的所有参数,比如像tag,userdata@H_502_56@
  • CCHttpRequest*_pHttpRequest;///thecorrespondingHttpRequestpointerwholeadstothisresponse@H_502_56@
  • bool@H_502_56@_succeed;///toindecateifthehttpreqeustissuccessfulsimply@H_502_56@
  • std::vector<char@H_502_56@>_responseData;///thereturnedrawdata.Youcanalsodumpitasastring@H_502_56@
  • int@H_502_56@_responseCode;///thestatuscodereturnedfromlibcurl,e.g.200,404@H_502_56@
  • std::string_errorBuffer;///if_responseCode!=200,pleaseread_errorBuffertofindthereason@H_502_56@
  • };

  • 说白了,CCHttpRequest和CCHttpResponse只不过是发送队列中的数据类型,和接收队列中的数据类型,是线程之间传递的参数,下面来说说CCHttpClient
    HttpClient.h

    copy

    @H_221_404@ //CCHttpClient是一个单例模式的类,整个程序共享一个实例对象@H_502_56@
  • class@H_502_56@CCHttpClient:public@H_502_56@CCObject
  • public@H_502_56@:
  • /**获取共享的单例对象**/@H_502_56@
  • static@H_502_56@CCHttpClient*getInstance();
  • /**Relasethesharedinstance**/@H_502_56@
  • static@H_502_56@void@H_502_56@destroyInstance();
  • /**
  • *Addagetrequesttotaskqueue
  • *@paramrequestaCCHttpRequestobject,whichincludesurl,responsecallbacketc.
  • pleasemakesurerequest->_requestDataisclearbeforecalling"send"here.
  • *@returnNULL
  • void@H_502_56@send(CCHttpRequest*request);
  • /**
  • *Changetheconnecttimeout
  • *@paramtimeout
  • inline@H_502_56@void@H_502_56@setTimeoutForConnect(int@H_502_56@value){_timeoutForConnect=value;};
  • *Getconnecttimeout
  • *@returnint
  • *
  • inline@H_502_56@int@H_502_56@getTimeoutForConnect(){return@H_502_56@_timeoutForConnect;}
  • *Changethedownloadtimeout
  • *@paramvalue
  • *@returnNULL
  • inline@H_502_56@void@H_502_56@setTimeoutForRead(int@H_502_56@value){_timeoutForRead=value;};
  • *Getdownloadtimeout
  • inline@H_502_56@int@H_502_56@getTimeoutForRead(){return@H_502_56@_timeoutForRead;};
  • private@H_502_56@:
  • CCHttpClient();
  • virtual@H_502_56@~CCHttpClient();
  • bool@H_502_56@init(void@H_502_56@);
  • *Initpthreadmutex,semaphore,andcreatenewthreadforhttprequests
  • *@returnbool
  • bool@H_502_56@lazyInitThreadSemphore();
  • /**Pollfunctioncalledfrommainthreadtodispatchcallbackswhenhttprequestsfinished**/@H_502_56@
  • void@H_502_56@dispatchResponseCallbacks(float@H_502_56@delta);
  • private@H_502_56@:
  • int@H_502_56@_timeoutForConnect;//连接超时时间@H_502_56@
  • int@H_502_56@_timeoutForRead;//接收数据超时时间@H_502_56@
  • //std::stringreqId;@H_502_56@
  • };

  • HttpClient.cpp

    copy
    @H_221_404@ static@H_502_56@pthread_ts_networkThread;//工作线程句柄@H_502_56@
  • static@H_502_56@pthread_mutex_ts_requestQueueMutex;//请求队列互斥变量@H_502_56@
  • static@H_502_56@pthread_mutex_ts_responseQueueMutex;//接收队列互斥变量@H_502_56@
  • static@H_502_56@sem_t*s_pSem=NULL;//用来驱动线程工作的信号量@H_502_56@
  • static@H_502_56@unsignedlong@H_502_56@s_asyncRequestCount=0;//当前需要处理的request个数@H_502_56@
  • #ifCC_TARGET_PLATFORM==CC_PLATFORM_IOS@H_502_56@
  • #defineCC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE1@H_502_56@
  • #else@H_502_56@
  • #defineCC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE0@H_502_56@
  • #endif@H_502_56@
  • #ifCC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE@H_502_56@
  • #defineCC_ASYNC_HTTPREQUEST_SEMAPHORE"ccHttpAsync"@H_502_56@
  • static@H_502_56@sem_ts_sem;
  • #if(CC_TARGET_PLATFORM==CC_PLATFORM_WIN32)@H_502_56@
  • typedef@H_502_56@int@H_502_56@int32_t;
  • static@H_502_56@bool@H_502_56@need_quit=false@H_502_56@;//退出标识@H_502_56@
  • static@H_502_56@CCArray*s_requestQueue=NULL;//请求队列(下面都说request队列)@H_502_56@
  • static@H_502_56@CCArray*s_responseQueue=NULL;//接收队列(下面都说response队列)@H_502_56@
  • static@H_502_56@CCHttpClient*s_pHttpClient=NULL;//全局单例CCHttpClient对象@H_502_56@
  • static@H_502_56@char@H_502_56@s_errorBuffer[CURL_ERROR_SIZE];//错误提示buffer@H_502_56@
  • typedef@H_502_56@size_t@H_502_56@(*write_callback)(void@H_502_56@*ptr,size_t@H_502_56@size,size_t@H_502_56@nmemb,void@H_502_56@*stream);//这个是用于cURL收到数据的回调函数@H_502_56@
  • //这个便是当cURL接收到数据回调的函数,也就是在这里对response进行填充,这里的声明方式和fwrite()函数一样@H_502_56@
  • size_t@H_502_56@writeData(void@H_502_56@*ptr,void@H_502_56@*stream)
  • //ptr指向接受到的数据,sizes为字节数@H_502_56@
  • //这里传过来的stream中保存了CCHttpResponse::_responseData@H_502_56@
  • std::vector<char@H_502_56@>*recvBuffer=(std::vector<char@H_502_56@>*)stream;
  • size_t@H_502_56@sizes=size*nmemb;
  • //adddatatotheendofrecvBuffer@H_502_56@
  • //将接受到的数据写到response中去@H_502_56@
  • recvBuffer->insert(recvBuffer->end(),(char@H_502_56@*)ptr,(char@H_502_56@*)ptr+sizes);
  • return@H_502_56@sizes;
  • //Prototypes@H_502_56@
  • bool@H_502_56@configureCURL(CURL*handle);
  • int@H_502_56@processGetTask(CCHttpRequest*request,write_callbackcallback,void@H_502_56@*stream,int32_t*errorCode);
  • int@H_502_56@processPostTask(CCHttpRequest*request,int32_t*errorCode);
  • //intprocessDownloadTask(HttpRequest*task,void*stream,int32_t*errorCode);@H_502_56@
  • //工作线程@H_502_56@
  • static@H_502_56@void@H_502_56@*networkThread(void@H_502_56@*data)
  • CCHttpRequest*request=NULL;
  • while@H_502_56@(true@H_502_56@)
  • //等待主线程发送信号,就是调用send()函数@H_502_56@
  • int@H_502_56@semWaitRet=sem_wait(s_pSem);
  • if@H_502_56@(semWaitRet<0){
  • CCLog("HttpRequestasyncthreadsemaphoreerror:%s\n"@H_502_56@,strerror(errno));
  • break@H_502_56@;
  • //退出@H_502_56@
  • if@H_502_56@(need_quit)
  • break@H_502_56@;
  • //step1:sendhttprequestiftherequestQueueisn'tempty@H_502_56@
  • request=NULL;
  • pthread_mutex_lock(&s_requestQueueMutex);//给request队列上锁@H_502_56@
  • if@H_502_56@(0!=s_requestQueue->count())
  • request=dynamic_cast@H_502_56@<CCHttpRequest*>(s_requestQueue->objectAtIndex(0));//取得第一个request@H_502_56@
  • s_requestQueue->removeObjectAtIndex(0);//将其移除队列@H_502_56@
  • //这里的request的引用次数为1,因为只有在send()函数中retain了一次@H_502_56@
  • pthread_mutex_unlock(&s_requestQueueMutex);//request队列解锁@H_502_56@
  • if@H_502_56@(NULL==request)
  • continue@H_502_56@;
  • //同步调用cURL库@H_502_56@
  • //使用request来创建一个response@H_502_56@
  • CCHttpResponse*response=new@H_502_56@CCHttpResponse(request);
  • //在CCHttpTtpResponse构造中,会将request再retain一次@H_502_56@
  • request->release();
  • //这里,只有response中有request的一次引用计数@H_502_56@
  • int@H_502_56@responseCode=-1;
  • int@H_502_56@retValue=0;
  • //根据请求类型设置cURL参数@H_502_56@
  • switch@H_502_56@(request->getRequestType())
  • case@H_502_56@CCHttpRequest::kHttpGet://HTTPGET@H_502_56@
  • retValue=processGetTask(request,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> writeData,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> response->getResponseData(),248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> &responseCode);
  • case@H_502_56@CCHttpRequest::kHttpPost://HTTPPOST@H_502_56@
  • retValue=processPostTask(request,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> writeData,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> response->getResponseData(),108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> &responseCode);
  • default@H_502_56@:
  • CCAssert(true@H_502_56@,"CCHttpClient:unkownrequesttype,onlyGETandPOStaresupported"@H_502_56@);
  • //设置返回代码@H_502_56@
  • response->setResponseCode(responseCode);
  • if@H_502_56@(retValue!=0)
  • response->setSucceed(false@H_502_56@);
  • response->setErrorBuffer(s_errorBuffer);
  • else@H_502_56@
  • response->setSucceed(true@H_502_56@);
  • //将response加入队列@H_502_56@
  • pthread_mutex_lock(&s_responseQueueMutex);//给response加锁@H_502_56@
  • s_responseQueue->addObject(response);
  • pthread_mutex_unlock(&s_responseQueueMutex);//解锁@H_502_56@
  • //启动CCScheduler调度@H_502_56@
  • CCDirector::sharedDirector()->getScheduler()->resuMetarget(CCHttpClient::getInstance());
  • //线程退出,清理request队列@H_502_56@
  • pthread_mutex_lock(&s_requestQueueMutex);
  • s_requestQueue->removeAllObjects();
  • pthread_mutex_unlock(&s_requestQueueMutex);
  • s_asyncRequestCount-=s_requestQueue->count();
  • if@H_502_56@(s_pSem!=NULL){
  • sem_unlink(CC_ASYNC_HTTPREQUEST_SEMAPHORE);
  • sem_close(s_pSem);
  • #else@H_502_56@
  • sem_destroy(s_pSem);
  • #endif@H_502_56@
  • s_pSem=NULL;
  • //释放互斥变量@H_502_56@
  • pthread_mutex_destroy(&s_requestQueueMutex);
  • pthread_mutex_destroy(&s_responseQueueMutex);
  • s_requestQueue->release();
  • s_responseQueue->release();
  • pthread_exit(NULL);
  • return@H_502_56@0;
  • //设置cURL超时属性@H_502_56@
  • bool@H_502_56@configureCURL(CURL*handle)
  • if@H_502_56@(!handle){
  • return@H_502_56@false@H_502_56@;
  • int32_tcode;
  • //设置错误信息缓冲@H_502_56@
  • code=curl_easy_setopt(handle,CURLOPT_ERRORBUFFER,s_errorBuffer);
  • if@H_502_56@(code!=CURLE_OK){
  • return@H_502_56@false@H_502_56@;
  • //设置超时时间@H_502_56@
  • code=curl_easy_setopt(handle,CURLOPT_TIMEOUT,CCHttpClient::getInstance()->getTimeoutForRead());
  • if@H_502_56@(code!=CURLE_OK){
  • return@H_502_56@true@H_502_56@;
  • //处理get方式请求@H_502_56@
  • //stream传递过来的是response->getResponseData()@H_502_56@
  • //关于cURL的东西这里就不多说了@H_502_56@
  • int@H_502_56@processGetTask(CCHttpRequest*request,int@H_502_56@*responseCode)
  • CURLcodecode=CURL_LAST;
  • //初始化cURL@H_502_56@
  • CURL*curl=curl_easy_init();
  • do@H_502_56@{
  • if@H_502_56@(!configureCURL(curl))//配置cURL@H_502_56@
  • /*handlecustomheaderdata*/@H_502_56@
  • /*createcurllinkedlist*/@H_502_56@
  • struct@H_502_56@curl_slist*cHeaders=NULL;
  • /*getcustomheaderdata(ifset)*/@H_502_56@
  • std::vector<std::string>headers=request->getHeaders();
  • if@H_502_56@(!headers.empty())
  • for@H_502_56@(std::vector<std::string>::iteratorit=headers.begin();it!=headers.end();it++)
  • /*appendcustomheadersonebyone*/@H_502_56@
  • cHeaders=curl_slist_append(cHeaders,it->c_str());
  • /*setcustomheadersforcurl*/@H_502_56@
  • code=curl_easy_setopt(curl,CURLOPT_HTTPHEADER,cHeaders);
  • if@H_502_56@(code!=CURLE_OK)
  • //这里将response->_responseData设置为cURL回调函数中的stream参数@H_502_56@
  • code=curl_easy_perform(curl);
  • /*freethelinkedlistforheaderdata*/@H_502_56@
  • curl_slist_free_all(cHeaders);
  • code=curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,responseCode);
  • if@H_502_56@(code!=CURLE_OK||*responseCode!=200)
  • code=CURLE_HTTP_RETURNED_ERROR;
  • }while@H_502_56@(0);
  • if@H_502_56@(curl){
  • curl_easy_cleanup(curl);
  • return@H_502_56@(code==CURLE_OK?0:1);
  • //这个就不说了,其实都一样的,cURL承担了所有工作@H_502_56@
  • int@H_502_56@processPostTask(CCHttpRequest*request,int32_t*responseCode)
  • CURLcodecode=CURL_LAST;
  • if@H_502_56@(!configureCURL(curl)){
  • /*handlecustomheaderdata*/@H_502_56@
  • /*createcurllinkedlist*/@H_502_56@
  • struct@H_502_56@curl_slist*cHeaders=NULL;
  • /*getcustomheaderdata(ifset)*/@H_502_56@
  • std::vector<std::string>headers=request->getHeaders();
  • if@H_502_56@(!headers.empty())
  • for@H_502_56@(std::vector<std::string>::iteratorit=headers.begin();it!=headers.end();it++)
  • /*appendcustomheadersonebyone*/@H_502_56@
  • cHeaders=curl_slist_append(cHeaders,it->c_str());
  • /*setcustomheadersforcurl*/@H_502_56@
  • code=curl_easy_setopt(curl,cHeaders);
  • code=curl_easy_perform(curl);
  • if@H_502_56@(code!=CURLE_OK||*responseCode!=200){
  • code=CURLE_HTTP_RETURNED_ERROR;
  • }while@H_502_56@(0);
  • //返回共享实例@H_502_56@
  • CCHttpClient*CCHttpClient::getInstance()
  • if@H_502_56@(s_pHttpClient==NULL){
  • s_pHttpClient=new@H_502_56@CCHttpClient();
  • return@H_502_56@s_pHttpClient;
  • void@H_502_56@CCHttpClient::destroyInstance()
  • CCAssert(s_pHttpClient,""@H_502_56@);
  • //将CCHttpClient::dispatchResponseCallbacks()函数从CCShecduler中取消挂载@H_502_56@
  • CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(schedule_selector(CCHttpClient::dispatchResponseCallbacks),s_pHttpClient);
  • s_pHttpClient->release();
  • CCHttpClient::CCHttpClient()
  • :_timeoutForConnect(30)
  • ,_timeoutForRead(60)
  • //将成员函数dispatchTesponseCallbacks()挂载至CCSheduler@H_502_56@
  • CCDirector::sharedDirector()->getScheduler()->scheduleSelector(
  • schedule_selector(CCHttpClient::dispatchResponseCallbacks),this@H_502_56@,false@H_502_56@);
  • //初始化为停止调度,由工作线程接收到了数据之后启用调度@H_502_56@
  • CCDirector::sharedDirector()->getScheduler()->pauseTarget(this@H_502_56@);
  • CCHttpClient::~CCHttpClient()
  • need_quit=true@H_502_56@;
  • sem_post(s_pSem);
  • s_pHttpClient=NULL;
  • //只有在第一次调用send()时调用,去初始化队列、创建线程、初始化互斥变量等@H_502_56@
  • bool@H_502_56@CCHttpClient::lazyInitThreadSemphore()
  • }else@H_502_56@{
  • s_pSem=sem_open(CC_ASYNC_HTTPREQUEST_SEMAPHORE,O_CREAT,0644,0);
  • if@H_502_56@(s_pSem==SEM_Failed){
  • CCLog("OpenHttpRequestSemaphoreFailed"@H_502_56@);
  • s_pSem=NULL;
  • int@H_502_56@semRet=sem_init(&s_sem,0);
  • if@H_502_56@(semRet<0){
  • CCLog("InitHttpRequestSemaphoreFailed"@H_502_56@);
  • s_pSem=&s_sem;
  • s_requestQueue=new@H_502_56@CCArray();
  • s_requestQueue->init();
  • s_responseQueue=new@H_502_56@CCArray();
  • s_responseQueue->init();
  • pthread_mutex_init(&s_requestQueueMutex,NULL);
  • pthread_mutex_init(&s_responseQueueMutex,NULL);
  • pthread_create(&s_networkThread,NULL,networkThread,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> pthread_detach(s_networkThread);
  • need_quit=false@H_502_56@;
  • //Addagettasktoqueue@H_502_56@
  • void@H_502_56@CCHttpClient::send(CCHttpRequest*request)
  • //第一次调用的时候初始化@H_502_56@
  • if@H_502_56@(false@H_502_56@==lazyInitThreadSemphore())
  • if@H_502_56@(!request)
  • //将当前需要处理的request个数++@H_502_56@
  • ++s_asyncRequestCount;
  • //在这里对request进行第一次retain,@H_502_56@
  • request->retain();
  • //这里request的引用次数为1@H_502_56@
  • pthread_mutex_lock(&s_requestQueueMutex);//request队列加锁@H_502_56@
  • s_requestQueue->addObject(request);//push到request队列@H_502_56@
  • pthread_mutex_unlock(&s_requestQueueMutex);//解锁@H_502_56@
  • //发送信号唤醒工作线程@H_502_56@
  • //将response队列数据分发@H_502_56@
  • void@H_502_56@CCHttpClient::dispatchResponseCallbacks(float@H_502_56@delta)
  • //CCLog("CCHttpClient::dispatchResponseCallbacksisrunning");@H_502_56@
  • CCHttpResponse*response=NULL;
  • pthread_mutex_lock(&s_responseQueueMutex);//给response队列上锁@H_502_56@
  • if@H_502_56@(s_responseQueue->count())
  • response=dynamic_cast@H_502_56@<CCHttpResponse*>(s_responseQueue->objectAtIndex(0));//取出response@H_502_56@
  • s_responseQueue->removeObjectAtIndex(0);//将其从response队列移除@H_502_56@
  • pthread_mutex_unlock(&s_responseQueueMutex);//解锁@H_502_56@
  • if@H_502_56@(response)
  • --s_asyncRequestCount;
  • CCHttpRequest*request=response->getHttpRequest();
  • CCObject*pTarget=request->getTarget();//获取request回调函数的对象@H_502_56@
  • SEL_CallFuncNDpSelector=request->getSelector();//获取回调函数@H_502_56@
  • if@H_502_56@(pTarget&&pSelector)
  • (pTarget->*pSelector)((CCNode*)this@H_502_56@,response);//调用回调函数,并把本单例对象和response传递给我们设置在request中的回调函数@H_502_56@
  • response->release();
  • if@H_502_56@(0==s_asyncRequestCount)//如果没有没有请求,停止调度@H_502_56@
  • }
  • 花了大半天时间,终于写的差不多了,其实我当初是想看看cocos2d-x是怎样封装socket这一块的,结果是这样,用的cURL库。。。
    这篇文章是我的处女做,哪里有不好的地方大家提出来共同进步,欢迎交流

    本人今年刚毕业,接触cocos2d-x也才两个月(写的不好不要扔砖就好),前一个多月一直在搞粒子系统这块,这几天把改造后的粒子系统工具开发完了,时间稍微多点,就看看其他的模块了,看完了收获也不少,由于经常逛csdn,拜读大神的文章,所以就想着咱也来发表一遍学习心得吧,这样既可以提高自己,也可以和大家交流交流心得,更重要的是我发现写博客可以提升学习的兴趣

    原文链接:https://www.f2er.com/cocos2dx/342281.html

    猜你在找的Cocos2d-x相关文章