例子:
void GameRequest::initRequset(const char* url, cocos2d::CCObject* pTarget, cocos2d::SEL_CallFuncND pSelector)
{
cocos2d::extension::CCHttpRequest* request = new cocos2d::extension::CCHttpRequest();
request->setUrl(url);
//设置为GET请求:kHttpGet
request->setRequestType(cocos2d::extension::CCHttpRequest::kHttpGet);
//设置处理响应回调函数
if(pTarget != NULL && pSelector != NULL){
request->setResponseCallback(pTarget, pSelector);
}
cocos2d::extension::CCHttpClient::getInstance()->setTimeoutForConnect(15);
cocos2d::extension::CCHttpClient::getInstance()->setTimeoutForRead(15);
cocos2d::extension::CCHttpClient::getInstance()->send(request);
int countme = request->retainCount();
if(countme <= 0)
{
CCLOG("=request retaincount==================%d",request->retainCount());
}
request->release();
}
void CoverScene::checkUserNameRequestCallBack(cocos2d::CCNode *sender, void *data)
{
cocos2d::extension::CCHttpResponse *response = (cocos2d::extension::CCHttpResponse*)data;
if (!response)
{
return;
}
//你可以使用: response->request->reqType获取请求类型
if (0 != strlen(response->getHttpRequest()->getTag()))
{
CCLog("%s completed", response->getHttpRequest()->getTag());
}
//获取状态码
int statusCode = response->getResponseCode();
char statusString[64] = {};
sprintf(statusString, "HTTP Status Code: %d, tag = %s", statusCode, response->getHttpRequest()->getTag());
CCLog("response code: %d", statusCode);
if (!response->isSucceed())
{
//访问失败获取错误信息
CCLog("response failed");
CCLog("error buffer: %s", response->getErrorBuffer());
return;
}
try {
vector::data
指针到 vector 类 的第一个元素成功或为空 vector 的位置。std::vector<char> *buffer = response->getResponseData();
std::string str = std::string(buffer->data(), buffer->size());
Json *dataJson = Json_create(str.data());
std::cout<<Json_getSize(dataJson)<<std::endl;
MessageBoxLayer::getMessageBoxPoint()->callMessageBoxRemove();
if (Json_getSize(dataJson) == 1)
{
//账号密码错误
CCLOG("账号密码错误.........");
changeToLogin();
}
else
{
Json *infoDataJson = Json_getItem(dataJson, "data");
m_accessToken = Json_getItem(infoDataJson,"token")->valuestring;
GameUser::GetGameUser()->uninqueId = atoll(Json_getItemAt(Json_getItemAt(dataJson, 1),0)->valuestring);
GameUser::GetGameUser()->platform_user_id = Json_getString(infoDataJson, "platform_user_id", "");//Json_String(infoDataJson, "platform_user_id");
CoverScene::m_iType = 0;
getServerListRequest();
}
}
catch (const std::exception& rhs)
{
CCLOG("数据异常");
}
#ifndef __CCHTTPREQUEST_H__
#define __CCHTTPREQUEST_H__
#include "cocos2d.h"
#include "ExtensionMacros.h"
#include "HttpRequest.h"
#include "HttpResponse.h"
NS_CC_EXT_BEGIN
/**
* @addtogroup Network
* @{
*/
/** @brief Singleton that handles(操控) asynchronous(asyn 异步 chromous 同步) http requests
* Once the request completed, a callback will issued(发布) in main thread when it provided during make request
*/
class CCHttpClient : public CCObject
{
public:
/** Return the shared instance **/
static CCHttpClient *getInstance();// CCHttpClient 是一个单例类
/** Relase the shared instance **/
static voiddestroyInstance();
{
CCAssert(s_pHttpClient, "");
CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(schedule_selector(CCHttpClient::dispatchResponseCallbacks), s_pHttpClient);
s_pHttpClient->release();
}
/**
* Add a get request to task queue
* @param request a CCHttpRequest object, which includes url, response callback etc.
please make sure request->_requestData is clear before calling "send" here.
* @return NULL
*/
voidsend(CCHttpRequest* request);//这个用的最多 将CCHttpRequest 加入请求列表
/**
* Change the connect timeout
* @param timeout
* @return NULL
*/
inline voidsetTimeoutForConnect(int value) {_timeoutForConnect = value;};//设置连接超时 时间值
/**
* Get connect timeout
* @return int
*
*/
inline int getTimeoutForConnect() {return _timeoutForConnect;}//获得连接时间
/**
* Change the download timeout
* @param value
* @return NULL
*/
inline voidsetTimeoutForRead(int value) {_timeoutForRead = value;};
/**
* Get download timeout
* @return int
*/
inline intgetTimeoutForRead() {return _timeoutForRead;};
private:
CCHttpClient();//单例类
: _timeoutForConnect(30)
, _timeoutForRead(60)
{
CCDirector::sharedDirector()->getScheduler()->scheduleSelector(
schedule_selector(CCHttpClient::dispatchResponseCallbacks), this, 0, false);
CCDirector::sharedDirector()->getScheduler()->pauseTarget(this);
}
virtual ~CCHttpClient();
//当类是在栈上 类在离开作用域时会调用析构函数释放空间,此时无法调用私有的析构函数
//如果在堆上分配空间,只有在delete时才会调用析构函数。
析构函数私有
当我们规定类只能在堆上分配内存时,就可以将析构函数声明为私有的。
class alloc
{
public:
alloc():
private:
~alloc();
};
如果在栈上分配空间,类在离开作用域时会调用析构函数释放空间,此时无法调用私有的析构函数。
如果在堆上分配空间,只有在delete时才会调用析构函数。
可以添加一个destroy()函数来释放,从而解决不能在析构函数中添加delete的问题。
class alloc
{
public:
alloc():
destroy(){ delete this;}
private:
~alloc();
};
/
bool init(void);
/**
* Init pthread mutex, semaphore, and create new thread for http requests
* @return bool
*/
boollazyInitThreadSemphore(); // 私有函数 无需深究 用到了许多额外函数 cpp里写的
{
if (s_requestQueue != NULL) {
return true;
} else {
s_requestQueue = new CCArray();
s_requestQueue->init();
s_responseQueue = new CCArray();
s_responseQueue->init();
pthread_mutex_init(&s_requestQueueMutex, NULL);
pthread_mutex_init(&s_responseQueueMutex, NULL);
pthread_mutex_init(&s_SleepMutex, NULL);
pthread_cond_init(&s_SleepCondition, NULL);
pthread_create(&s_networkThread, NULL, networkThread, NULL);
pthread_detach(s_networkThread);
need_quit = false;
}
return true;
}
//Poll function called from main thread to dispatch callbacks when http requests finished
// Poll and notify main thread if responses exists in queue
voiddispatchResponseCallbacks(float delta); // 分发网络回应 私有函数 无需深究
private:
int _timeoutForConnect;
int _timeoutForRead;
// std::string reqId;
};
// end of Network group
/// @}
NS_CC_EXT_END
#endif //__CCHTTPREQUEST_H__
#include "HttpClient.h"
// #include "platform/CCThread.h"
#include <queue>
#include <pthread.h>
#include <errno.h>
#include "curl/curl.h"
NS_CC_EXT_BEGIN
static pthread_t s_networkThread;
static pthread_mutex_t s_requestQueueMutex;
static pthread_mutex_t s_responseQueueMutex;
static pthread_mutex_ts_SleepMutex;
static pthread_cond_ts_SleepCondition;
static unsigned long s_asyncRequestCount = 0;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
typedef int int32_t;
#endif
static bool need_quit = false;
static CCArray* s_requestQueue = NULL;
static CCArray* s_responseQueue = NULL;
static CCHttpClient *s_pHttpClient = NULL; // pointer to singleton
static char s_errorBuffer[CURL_ERROR_SIZE];
typedef size_t (*write_callback)(void *ptr, size_t size, size_t nmemb, void *stream);
// Callback function used by libcurl for collect response data
static size_t writeData(void *ptr, size_t size, size_t nmemb, void *stream)
{
std::vector<char> *recvBuffer = (std::vector<char>*)stream;
size_t sizes = size * nmemb;
// add data to the end of recvBuffer
// write data maybe called more than once in a single request
recvBuffer->insert(recvBuffer->end(), (char*)ptr, (char*)ptr+sizes);
return sizes;
}
// Callback function used by libcurl for collect header data
static size_t writeHeaderData(void *ptr, size_t size, size_t nmemb, void *stream)
{
std::vector<char> *recvBuffer = (std::vector<char>*)stream;
size_t sizes = size * nmemb;
// add data to the end of recvBuffer
// write data maybe called more than once in a single request
recvBuffer->insert(recvBuffer->end(), (char*)ptr, (char*)ptr+sizes);
return sizes;
}
static int processGetTask(CCHttpRequest *request, write_callback callback, void *stream, int32_t *errorCode, write_callback headerCallback, void *headerStream);
static int processPostTask(CCHttpRequest *request, write_callback callback, void *stream, int32_t *errorCode, write_callback headerCallback, void *headerStream);
static int processPutTask(CCHttpRequest *request, write_callback callback, void *stream, int32_t *errorCode, write_callback headerCallback, void *headerStream);
static int processDeleteTask(CCHttpRequest *request, write_callback callback, void *stream, int32_t *errorCode, write_callback headerCallback, void *headerStream);
// int processDownloadTask(HttpRequest *task, write_callback callback, void *stream, int32_t *errorCode);
// Worker thread
static void* networkThread(void *data)
{
CCHttpRequest *request = NULL;
while (true)
{
if (need_quit)
{
break;
}
// step 1: send http request if the requestQueue isn't empty
request = NULL;
pthread_mutex_lock(&s_requestQueueMutex); //Get request task from queue
if (0 != s_requestQueue->count())
{
request = dynamic_cast<CCHttpRequest*>(s_requestQueue->objectAtIndex(0));
s_requestQueue->removeObjectAtIndex(0);
// request's refcount = 1 here
}
pthread_mutex_unlock(&s_requestQueueMutex);
if (NULL == request)
{
// Wait for http request tasks from main thread
pthread_cond_wait(&s_SleepCondition, &s_SleepMutex);
continue;
}
// step 2: libcurl sync access
// Create a HttpResponse object, the default setting is http access failed
CCHttpResponse *response = new CCHttpResponse(request);
// request's refcount = 2 here, it's retained by HttpRespose constructor
request->release();
// ok, refcount = 1 now, only HttpResponse hold it.
int32_t responseCode = -1;
int retValue = 0;
// Process the request -> get response packet
switch (request->getRequestType())
{
case CCHttpRequest::kHttpGet: // HTTP GET
retValue = processGetTask(request,
writeData,
response->getResponseData(),
&responseCode,
writeHeaderData,
response->getResponseHeader());
break;
case CCHttpRequest::kHttpPost: // HTTP POST
retValue = processPostTask(request,
writeData,
response->getResponseData(),
&responseCode,
writeHeaderData,
response->getResponseHeader());
break;
case CCHttpRequest::kHttpPut:
retValue = processPutTask(request,
writeData,
response->getResponseData(),
&responseCode,
writeHeaderData,
response->getResponseHeader());
break;
case CCHttpRequest::kHttpDelete:
retValue = processDeleteTask(request,
writeData,
response->getResponseData(),
&responseCode,
writeHeaderData,
response->getResponseHeader());
break;
default:
CCAssert(true, "CCHttpClient: unkown request type, only GET and POSt are supported");
break;
}
// write data to HttpResponse
response->setResponseCode(responseCode);
if (retValue != 0)
{
response->setSucceed(false);
response->setErrorBuffer(s_errorBuffer);
}
else
{
response->setSucceed(true);
}
// add response packet into queue
pthread_mutex_lock(&s_responseQueueMutex);
s_responseQueue->addObject(response);
pthread_mutex_unlock(&s_responseQueueMutex);
// resume dispatcher selector
CCDirector::sharedDirector()->getScheduler()->resumeTarget(CCHttpClient::getInstance());
}
// cleanup: if worker thread received quit signal, clean up un-completed request queue
pthread_mutex_lock(&s_requestQueueMutex);
s_requestQueue->removeAllObjects();
pthread_mutex_unlock(&s_requestQueueMutex);
s_asyncRequestCount -= s_requestQueue->count();
if (s_requestQueue != NULL) {
pthread_mutex_destroy(&s_requestQueueMutex);
pthread_mutex_destroy(&s_responseQueueMutex);
pthread_mutex_destroy(&s_SleepMutex);
pthread_cond_destroy(&s_SleepCondition);
s_requestQueue->release();
s_requestQueue = NULL;
s_responseQueue->release();
s_responseQueue = NULL;
}
pthread_exit(NULL);
return 0;
}
//Configure curl's timeout property
static bool configureCURL(CURL *handle)
{
if (!handle) {
return false;
}
int32_t code;
code = curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, s_errorBuffer);
if (code != CURLE_OK) {
return false;
}
code = curl_easy_setopt(handle, CURLOPT_TIMEOUT, CCHttpClient::getInstance()->getTimeoutForRead());
if (code != CURLE_OK) {
return false;
}
code = curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, CCHttpClient::getInstance()->getTimeoutForConnect());
if (code != CURLE_OK) {
return false;
}
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L);
return true;
}
class CURLRaii
{
/// Instance of CURL
CURL *m_curl;
/// Keeps custom header data
curl_slist *m_headers;
public:
CURLRaii()
: m_curl(curl_easy_init())
, m_headers(NULL)
{
}
~CURLRaii()
{
if (m_curl)
curl_easy_cleanup(m_curl);
/* free the linked list for header data */
if (m_headers)
curl_slist_free_all(m_headers);
}
template <class T>
bool setOption(CURLoption option, T data)
{
return CURLE_OK == curl_easy_setopt(m_curl, option, data);
}
/**
* @brief Inits CURL instance for common usage
* @param request Null not allowed
* @param callback Response write callback
* @param stream Response write stream
*/
bool init(CCHttpRequest *request, write_callback callback, void *stream, write_callback headerCallback, void *headerStream)
{
if (!m_curl)
return false;
if (!configureCURL(m_curl))
return false;
/* get custom header data (if set) */
std::vector<std::string> headers=request->getHeaders();
if(!headers.empty())
{
/* append custom headers one by one */
for (std::vector<std::string>::iterator it = headers.begin(); it != headers.end(); ++it)
m_headers = curl_slist_append(m_headers,it->c_str());
/* set custom headers for curl */
if (!setOption(CURLOPT_HTTPHEADER, m_headers))
return false;
}
return setOption(CURLOPT_URL, request->getUrl())
&& setOption(CURLOPT_WRITEFUNCTION, callback)
&& setOption(CURLOPT_WRITEDATA, stream)
&& setOption(CURLOPT_HEADERFUNCTION, headerCallback)
&& setOption(CURLOPT_HEADERDATA, headerStream);
}
/// @param responseCode Null not allowed
bool perform(int *responseCode)
{
if (CURLE_OK != curl_easy_perform(m_curl))
return false;
CURLcode code = curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, responseCode);
if (code != CURLE_OK || *responseCode != 200)
return false;
// Get some mor data.
return true;
}
};
//Process Get Request
static int processGetTask(CCHttpRequest *request, write_callback callback, void *stream, int32_t *responseCode, write_callback headerCallback, void *headerStream)
{
CURLRaii curl;
bool ok = curl.init(request, callback, stream, headerCallback, headerStream)
&& curl.setOption(CURLOPT_FOLLOWLOCATION, true)
&& curl.perform(responseCode);
return ok ? 0 : 1;
}
//Process POST Request
static int processPostTask(CCHttpRequest *request, write_callback callback, void *stream, int32_t *responseCode, write_callback headerCallback, void *headerStream)
{
CURLRaii curl;
bool ok = curl.init(request, callback, stream, headerCallback, headerStream)
&& curl.setOption(CURLOPT_POST, 1)
&& curl.setOption(CURLOPT_POSTFIELDS, request->getRequestData())
&& curl.setOption(CURLOPT_POSTFIELDSIZE, request->getRequestDataSize())
&& curl.perform(responseCode);
return ok ? 0 : 1;
}
//Process PUT Request
static int processPutTask(CCHttpRequest *request, write_callback callback, void *stream, int32_t *responseCode, write_callback headerCallback, void *headerStream)
{
CURLRaii curl;
bool ok = curl.init(request, callback, stream, headerCallback, headerStream)
&& curl.setOption(CURLOPT_CUSTOMREQUEST, "PUT")
&& curl.setOption(CURLOPT_POSTFIELDS, request->getRequestData())
&& curl.setOption(CURLOPT_POSTFIELDSIZE, request->getRequestDataSize())
&& curl.perform(responseCode);
return ok ? 0 : 1;
}
//Process DELETE Request
static int processDeleteTask(CCHttpRequest *request, write_callback callback, void *stream, int32_t *responseCode, write_callback headerCallback, void *headerStream)
{
CURLRaii curl;
bool ok = curl.init(request, callback, stream, headerCallback, headerStream)
&& curl.setOption(CURLOPT_CUSTOMREQUEST, "DELETE")
&& curl.setOption(CURLOPT_FOLLOWLOCATION, true)
&& curl.perform(responseCode);
return ok ? 0 : 1;
}
// HttpClient implementation
CCHttpClient* CCHttpClient::getInstance()
{
if (s_pHttpClient == NULL) {
s_pHttpClient = new CCHttpClient();
}
return s_pHttpClient;
}
void CCHttpClient::destroyInstance()
{
CCAssert(s_pHttpClient, "");
CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(schedule_selector(CCHttpClient::dispatchResponseCallbacks), s_pHttpClient);
s_pHttpClient->release();
}
CCHttpClient::CCHttpClient()
: _timeoutForConnect(30)
, _timeoutForRead(60)
{
CCDirector::sharedDirector()->getScheduler()->scheduleSelector(
schedule_selector(CCHttpClient::dispatchResponseCallbacks), this, 0, false);
CCDirector::sharedDirector()->getScheduler()->pauseTarget(this);
}
CCHttpClient::~CCHttpClient()
{
need_quit = true;
if (s_requestQueue != NULL) {
pthread_cond_signal(&s_SleepCondition);
}
s_pHttpClient = NULL;
}
//Lazy create semaphore & mutex & thread
bool CCHttpClient::lazyInitThreadSemphore()
{
if (s_requestQueue != NULL) {
return true;
} else {
s_requestQueue = new CCArray();
s_requestQueue->init();
s_responseQueue = new CCArray();
s_responseQueue->init();
pthread_mutex_init(&s_requestQueueMutex, NULL);
pthread_mutex_init(&s_responseQueueMutex, NULL);
pthread_mutex_init(&s_SleepMutex, NULL);
pthread_cond_init(&s_SleepCondition, NULL);
pthread_create(&s_networkThread, NULL, networkThread, NULL);
pthread_detach(s_networkThread);
need_quit = false;
}
return true;
}
//Add a get task to queue
void CCHttpClient::send(CCHttpRequest* request)
{
if (false == lazyInitThreadSemphore())
{
return;
}
if (!request)
{
return;
}
++s_asyncRequestCount;
request->retain();
pthread_mutex_lock(&s_requestQueueMutex);
s_requestQueue->addObject(request);
pthread_mutex_unlock(&s_requestQueueMutex);
// Notify thread start to work
pthread_cond_signal(&s_SleepCondition);
}
// Poll and notify main thread if responses exists in queue
void CCHttpClient::dispatchResponseCallbacks(float delta)
{
// CCLog("CCHttpClient::dispatchResponseCallbacks is running");
CCHttpResponse* response = NULL;
pthread_mutex_lock(&s_responseQueueMutex);
if (s_responseQueue->count())
{
response = dynamic_cast<CCHttpResponse*>(s_responseQueue->objectAtIndex(0));
s_responseQueue->removeObjectAtIndex(0);
}
pthread_mutex_unlock(&s_responseQueueMutex);
if (response)
{
--s_asyncRequestCount;
CCHttpRequest *request = response->getHttpRequest();
CCObject *pTarget = request->getTarget();
SEL_HttpResponse pSelector = request->getSelector();
if (pTarget && pSelector)
{
(pTarget->*pSelector)(this, response);
}
response->release();
}
if (0 == s_asyncRequestCount)
{
CCDirector::sharedDirector()->getScheduler()->pauseTarget(this);
}
}
NS_CC_EXT_END