详细实现
//一些配置 //两个队列的 互斥量 static std::mutex s_requestQueueMutex; static std::mutex s_responseQueueMutex; //条件变量 static std::condition_variable_any s_SleepCondition; //两个请求队列 static Vector<HttpRequest*>* s_requestQueue = nullptr; static Vector<HttpResponse*>* s_responseQueue = nullptr; //单例的 HTTPClient static HttpClient *s_pHttpClient = nullptr; // pointer to singleton //错误缓冲 static char s_errorBuffer[CURL_ERROR_SIZE] = {0}; //write_callback typedef size_t (*write_callback)(void *ptr, size_t size, size_t nmemb, void *stream); //cookie文件名 static std::string s_cookieFilename = ""; //SSL证书 位置 static std::string s_sslCaFilename = ""; //一个准备的请求对象 哨兵请求 用来当HttpClient 析构时 通知 工作线程退出 static HttpRequest *s_requestSentinel = new HttpRequest; // libcurl 用来收集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; //写入到stream中 recvBuffer->insert(recvBuffer->end(), (char*)ptr, (char*)ptr+sizes); return sizes; } // libcurl 用来收集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; //同理 recvBuffer->insert(recvBuffer->end(), (char*)ptr, (char*)ptr+sizes); return sizes; }两个重要的工作线程
// Worker thread void HttpClient::networkThread() { auto scheduler = Director::getInstance()->getScheduler(); while (true) { HttpRequest *request; // step 1: send http request if the requestQueue isn't empty { //获取请求队列的锁 std::lock_guard<std::mutex> lock(s_requestQueueMutex); //如果为空 就要sleep while (s_requestQueue->empty()) { s_SleepCondition.wait(s_requestQueueMutex); } //否则 取出第一个需求 request = s_requestQueue->at(0); s_requestQueue->erase(0); } //是哨兵 就结束 if (request == s_requestSentinel) { break; } // step 2: libcurl sync access // Create a HttpResponse object, the default setting is http access failed //开始 包装response对象 HttpResponse *response = new (std::nothrow) HttpResponse(request); //开始处理 processResponse(response, s_errorBuffer); //处理完成了 放到response队列里面去 // add response packet into queue s_responseQueueMutex.lock(); s_responseQueue->pushBack(response); s_responseQueueMutex.unlock(); //放到主线程去执行 回调 //每次处理一个 通知一次回调 注意不是每帧调用 或定时调用 只是这一次 if (nullptr != s_pHttpClient) { scheduler->performFunctionInCocosThread(CC_CALLBACK_0(HttpClient::dispatchResponseCallbacks, this)); } } //说明 全部处理完了 清理一下 s_requestQueueMutex.lock(); s_requestQueue->clear(); s_requestQueueMutex.unlock(); //不为空 就删除队列 if (s_requestQueue != nullptr) { delete s_requestQueue; s_requestQueue = nullptr; delete s_responseQueue; s_responseQueue = nullptr; } } //单独处理 一个请求 void HttpClient::networkThreadAlone(HttpRequest* request) { // Create a HttpResponse object, the default setting is http access failed HttpResponse *response = new (std::nothrow) HttpResponse(request); char errorBuffer[CURL_ERROR_SIZE] = { 0 }; //处理完了 之后 processResponse(response, errorBuffer); //注册回调 auto scheduler = Director::getInstance()->getScheduler(); //单独注册 scheduler->performFunctionInCocosThread([response, request]{ const ccHttpRequestCallback& callback = request->getCallback(); Ref* pTarget = request->getTarget(); SEL_HttpResponse pSelector = request->getSelector(); //这几种回调 看有哪一个 if (callback != nullptr) { callback(s_pHttpClient, response); } else if (pTarget && pSelector) { (pTarget->*pSelector)(s_pHttpClient, response); } //手动释放 response->release(); // do not release in other thread request->release(); }); }可以看到对待每一个request,都对其执行 processResponse
//传入 Request封装成的Response 并传入errorBuffer // Process Response static void processResponse(HttpResponse* response, char* errorBuffer) { 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(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader(), errorBuffer); break; case HttpRequest::Type::POST: // HTTP POST retValue = processPostTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader(), errorBuffer); break; case HttpRequest::Type::PUT: retValue = processPutTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader(), errorBuffer); break; case HttpRequest::Type::DELETE: retValue = processDeleteTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader(), errorBuffer); 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(errorBuffer); } else { response->setSucceed(true); } } //Process Get Request static int processGetTask(HttpRequest *request, write_callback callback, void *stream, long *responseCode, write_callback headerCallback, void *headerStream, char *errorBuffer) { //整个 网络功能 都是对curl库的封装 CURLRaii curl; bool ok = curl.init(request, callback, stream, headerCallback, headerStream, errorBuffer) && curl.setOption(CURLOPT_FOLLOWLOCATION, true) && curl.perform(responseCode); return ok ? 0 : 1; } //Process POST Request static int processPostTask(HttpRequest *request, write_callback callback, void *stream, long *responseCode, write_callback headerCallback, void *headerStream, char *errorBuffer) { CURLRaii curl; bool ok = curl.init(request, callback, stream, headerCallback, headerStream, errorBuffer) && 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(HttpRequest *request, write_callback callback, void *stream, long *responseCode, write_callback headerCallback, void *headerStream, char *errorBuffer) { CURLRaii curl; bool ok = curl.init(request, callback, stream, headerCallback, headerStream, errorBuffer) && 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(HttpRequest *request, write_callback callback, void *stream, long *responseCode, write_callback headerCallback, void *headerStream, char *errorBuffer) { CURLRaii curl; bool ok = curl.init(request, callback, stream, headerCallback, headerStream, errorBuffer) && curl.setOption(CURLOPT_CUSTOMREQUEST, "DELETE") && curl.setOption(CURLOPT_FOLLOWLOCATION, true) && curl.perform(responseCode); return ok ? 0 : 1; }下一篇,分析 多分辨率支持 的实现。
