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请求
  2. voidHttpClientTest::onMenuGetTestClicked(cocos2d::CCObject*sender)
  3. {
  4. //test1
  5. CCHttpRequest*request=newCCHttpRequest();//创建request对象,这里new出来的对象不能使用autorelease(),原因后述
  6. request->setUrl("http://just-make-this-request-Failed.com");//设置url
  7. request->setRequestType(CCHttpRequest::kHttpGet);//设置请求方式
  8. request->setResponseCallback(this,callfuncND_selector(HttpClientTest::onHttpRequestCompleted));//这是回调对象和回调函数
  9. request->setTag("GETtest1");//设置用户标识,可以通过response获取
  10. CCHttpClient::getInstance()->send(request);//使用CCHttpClient共享实例来发送request
  11. request->release();//调用release()
  12. }
  13. //waiting
  14. m_labelStatusCode->setString("waiting...");
  15. }
  16. //这里就是我们要处理接收到数据的回调函数了,sender为CCHttpClient实例指针,data为接收到的response指针
  17. voidHttpClientTest::onHttpRequestCompleted(cocos2d::CCNode*sender,void*data)
  18. CCHttpResponse*response=(CCHttpResponse*)data;
  19. if(!response)
  20. return;
  21. //获取对应request的字符串标识
  22. if(0!=strlen(response->getHttpRequest()->getTag()))
  23. CCLog("%scompleted",response->getHttpRequest()->getTag());
  24. //获取返回代码,比如200、404
  25. intstatusCode=response->getResponseCode();
  26. charstatusString[64]={};
  27. sprintf(statusString,"HTTPStatusCode:%d,tag=%s",statusCode,response->getHttpRequest()->getTag());
  28. m_labelStatusCode->setString(statusString);
  29. CCLog("responsecode:%d",statusCode);
  30. if(!response->isSucceed())
  31. {
  32. CCLog("responseFailed");
  33. CCLog("errorbuffer:%s",response->getErrorBuffer());//可以调用getErrorBuffer()来获取错误原因
  34. return;
  35. //dumpdata
  36. std::vector<char>*buffer=response->getResponseData();//用来获取接收到的数据
  37. printf("HttpTest,dumpdata:");
  38. for(unsignedinti=0;i<buffer->size();i++)
  39. printf("%c",(*buffer)[i]);
  40. printf("\n");
  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_795_404@ classCCHttpRequest:publicCCObject
  • public:
  • /**请求类型枚举,可以通过setReqeustType(param)设置*/
  • typedefenum
  • 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一次
  • 具体的后文有
  • */
  • CCHttpRequest()
  • _requestType=kHttpUnkown;
  • _url.clear();
  • _requestData.clear();
  • _tag.clear();
  • _pTarget=NULL;
  • _pSelector=NULL;
  • _pUserData=NULL;
  • };
  • virtual~CCHttpRequest()
  • if(_pTarget)
  • _pTarget->release();
  • /**重载autorelease函数禁止调用*/
  • CCObject*autorelease(void)
  • CCAssert(false,"HttpResponseisusedbetweennetworkthreadanduithread\
  • therefore,autoreleaseisforbiddenhere");
  • returnNULL;
  • //setter/gettersforproperties
  • /**设置请求类型
  • 目前支持kHttpGet和kHttpPost
  • inlinevoidsetRequestType(HttpRequestTypetype)
  • _requestType=type;
  • /**返回请求类型*/
  • inlineHttpRequestTypegetRequestType()
  • return_requestType;
  • };
  • /**设置请求url
  • inlinevoidsetUrl(constchar*url)
  • _url=url;
  • /**获取请求url*/
  • inlineconstchar*getUrl()
  • return_url.c_str();
  • /**这个设置用于post方式的data数据
  • inlinevoidsetRequestData(constchar*buffer,unsignedintlen)
  • _requestData.assign(buffer,buffer+len);
  • /**Gettherequestdatapointerback*/
  • inlinechar*getRequestData()
  • return&(_requestData.front());
  • /**Getthesizeofrequestdataback*/
  • inlineintgetRequestDataSize()
  • return_requestData.size();
  • /**为每个请求设置一个字符串标示,可以通过HttpResponse->getHttpRequest->getTag()获取,因为HttpResponse会将对应的HttpRequest封装在里面
  • */
  • inlinevoidsetTag(constchar*tag)
  • _tag=tag;
  • /**Getthestringtagbacktoidentifytherequest.
  • ThebestpracticeistouseitinyourMyClass::onMyHttpRequestCompleted(sender,HttpResponse*)callback
  • inlineconstchar*getTag()
  • return_tag.c_str();
  • /**Optionfield.Youcanattachacustomeddataineachrequest,andgetitbackinresponsecallback.
  • Butyouneedtonew/deletethedatapointermanully
  • inlinevoidsetUserData(void*pUserData)
  • _pUserData=pUserData;
  • /**Getthepre-settedcustomdatapointerback.
  • Don'tforgettodeleteit.HttpClient/HttpResponse/HttpRequestwilldonothingwiththispointer
  • inlinevoid*getUserData()
  • return_pUserData;
  • /**通过这个函数设置我们的数据处理回调函数
  • inlinevoidsetResponseCallback(CCObject*pTarget,SEL_CallFuncNDpSelector)
  • _pTarget=pTarget;
  • _pSelector=pSelector;
  • _pTarget->retain();
  • /**Getthetargetofcallbackselectorfuntion,mainlyusedbyCCHttpClient*/
  • inlineCCObject*getTarget()
  • return_pTarget;
  • /**Gettheselectorfunctionpointer,mainlyusedbyCCHttpClient*/
  • inlineSEL_CallFuncNDgetSelector()
  • return_pSelector;
  • /**Setanycustomheaders**/
  • inlinevoidsetHeaders(std::vector<std::string>pHeaders)
  • _headers=pHeaders;
  • /**Getcustomheaders**/
  • inlinestd::vector<std::string>getHeaders()
  • return_headers;
  • protected:
  • //properties
  • HttpRequestType_requestType;///请求方式
  • std::string_url;///请求url
  • std::vector<char>_requestData;///用于POST
  • std::string_tag;///用户自定义标识,可以用来在response回调中区分request
  • CCObject*_pTarget;///回调对象
  • SEL_CallFuncND_pSelector;///回调函数例如MyLayer::onHttpResponse(CCObject*sender,void*data)
  • void*_pUserData;///用户自定义数据,和_tag用法一样,只不过是用途不一样
  • std::vector<std::string>_headers;///customhttpheaders
  • };

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

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

    copy

    @H_795_404@ //CCHttpClient是一个单例模式的类,整个程序共享一个实例对象
  • classCCHttpClient:publicCCObject
  • public:
  • /**获取共享的单例对象**/
  • staticCCHttpClient*getInstance();
  • /**Relasethesharedinstance**/
  • staticvoiddestroyInstance();
  • /**
  • *Addagetrequesttotaskqueue
  • *@paramrequestaCCHttpRequestobject,whichincludesurl,responsecallbacketc.
  • pleasemakesurerequest->_requestDataisclearbeforecalling"send"here.
  • *@returnNULL
  • voidsend(CCHttpRequest*request);
  • /**
  • *Changetheconnecttimeout
  • *@paramtimeout
  • inlinevoidsetTimeoutForConnect(intvalue){_timeoutForConnect=value;};
  • *Getconnecttimeout
  • *@returnint
  • *
  • inlineintgetTimeoutForConnect(){return_timeoutForConnect;}
  • *Changethedownloadtimeout
  • *@paramvalue
  • *@returnNULL
  • inlinevoidsetTimeoutForRead(intvalue){_timeoutForRead=value;};
  • *Getdownloadtimeout
  • inlineintgetTimeoutForRead(){return_timeoutForRead;};
  • private:
  • CCHttpClient();
  • virtual~CCHttpClient();
  • boolinit(void);
  • *Initpthreadmutex,semaphore,andcreatenewthreadforhttprequests
  • *@returnbool
  • boollazyInitThreadSemphore();
  • /**Pollfunctioncalledfrommainthreadtodispatchcallbackswhenhttprequestsfinished**/
  • voiddispatchResponseCallbacks(floatdelta);
  • private:
  • int_timeoutForConnect;//连接超时时间
  • int_timeoutForRead;//接收数据超时时间
  • //std::stringreqId;
  • };

  • HttpClient.cpp

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

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

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