代号NSLG官网在哪下载 最新官方下载安装地址,
时间:2023-10-05 15:19:52
来源:
浏览:
网络通信5:HTTP下载器
游戏开发中需要动态下载资源。甚至支持热更新修复代码。都需要引擎支持文件下载功能。写个基于http协议的多线程文件下载器。用第三方库如何选择问题?如何实现接口方便调用问题?等等。其实前面也多次用到libcurl。libcurl作为是一个多协议的便于客户端使用的URL传输库。libcurl已经非常灵活。接口设计的非常细。完全可以满足需求。
这里分享一个基于libcurl的HTTP封装类,其功能包括:同步的(HTTP/HTTPS)GET、POST请求,以及文件下载和进度报告。通过网络通信1-5中通信相关的方式。游戏开发中用到的通信基本都囊括了。引擎底层已经具备了强大的通信能力和提供完善的接口。后续的重点就是如何使用好接口。和提高开发效率。尤其是团队中多人参与研发。如何高效协助的问题。必然需要完整的工具链实现网络消息生成。使真正开发者无需关注底层。只需依葫芦画瓢接收和发送消息即可。但作为游戏开发者还是需要多花些精力去实现下。知识大爆炸时代更需要组织代码能力强的人才。尽量减少代码编程的时间。
C++实现下载器类:Gk8HttpLoader.h
#ifndef __GK8HTTPLOADER_H__ #define __GK8HTTPLOADER_H__ #pragma once #include "Gk8BaseObj.h" #include "Gk8ByteMaker.h" #include "curl/curl.h" #define GK8LOADER_COUNT 0x0001 #define GK8LOADER_SIZE 0x0002 #define GK8LOADER_ONESIZE 0x0003 class Gk8HttpLoader:public Gk8BaseObj { DECLARE_TOSPP_MAP; private: GK8_BOOL m_bLoading; //是否正在文件下载 Gk8ByteMaker m_iFileBufData; //<文件BUFF数据> GK8_INT m_nLoadShowCase; //<下载显示模式:1个数进度,2整体大小进度,3单个大小进度> Gk8Var m_iLoadProgressCallVar; Gk8Var m_iLoadFinishCallVar; GK8_INT m_nLoadFileCount; //<已下载文件个数> GK8_INT m_nSumFileCount; //<总文件个数> GK8_INT m_nLoadFileSize; //<已下载文件大小> GK8_INT m_nSumFileSize; //<总文件大小> private: GK8_BOOL InitLoaderThreadSemphore(); public: Gk8HttpLoader(); virtual ~Gk8HttpLoader(); static Gk8HttpLoader* GetInstance(); GK8_VOID Destroy(); GK8_VOID TOSPPFUNC AddLoaderFile(GK8_LPCSTR lpFileName,GK8_LPCSTR lpLoaderUrl,GK8_LPCSTR lpLocalFile,GK8_INT nFileSize); GK8_VOID TOSPPFUNC SetHttpLoad(GK8_INT nLoadShowCase,Gk8Var& iLoadProgressCallVar,Gk8Var& iLoadFinishCallVar); GK8_VOID TOSPPFUNC HttpLoaderFile(); ; GK8_VOID OnProgress(GK8_LPVOID lpLoaderData,GK8_CDOUBLE dlTotal,GK8_CDOUBLE dlNow); GK8_VOID ShowLoadBar(GK8_LPVOID lpLoaderData); GK8_VOID HttpLoaderTick(); }; #endif
C++实现下载器类:Gk8HttpLoader.cpp
#include "Gk8HttpLoader.h" #include "Gk8OperSys.h" #include "Gk8SetMb.cpp" #include "Gk8BufEntry.cpp" #include "Gk8FileUtil.h" #include <queue> #include <pthread.h> #include <semaphore.h> #include <errno.h> #include <fcntl.h> typedef struct tagLOADERDATA { GK8_UINT nNameId; //<文件名ID> GK8_LPCSTR pFileName; //<下载文件名> GK8_LPCSTR pLoaderUrl; //<下载HTTP URL> GK8_LPCSTR pLocalFile; //<本地文件存放地> GK8_INT nFileSize; //<文件大小> Gk8ByteMaker* pFileBufData; //<文件BUFF数据> GK8_BOOL bSucceed; // GK8_INT nResponseCode; // Gk8Str sErrorBuffer; // }LOADERDATA,*LPLOADERDATA; static Gk8Str sg_iLoadProgressEvent("OnLoadProgress"); //<下载进度信息> static Gk8Str sg_iLoadFinishEvent("OnLoadFinish"); //<下载完成信息> static Gk8HttpLoader* sg_pHttpLoader=NULL; //<静态HTTP下载器> static Gk8BufEntry<LOADERDATA,256>* s_pLoaderCache=NULL; static GK8_BOOL sg_bHttpLoaderQuit=false; //<退出HTTP下载器> static sem_t* sg_pLoaderSem=NULL; //<信号量的数据类型> //<线程及互斥定义> static pthread_t sg_LoaderNetWorkThread; // static pthread_mutex_t sg_RequestLoaderMutex; // static pthread_mutex_t sg_ResponseLoaderMutex; // static Gk8SetMb<LPLOADERDATA> sg_iRequestLoaderQueue; // static Gk8SetMb<LPLOADERDATA> sg_iResponseLoaderQueue; // static GK8_CHAR sg_szLoaderErrorBuf; //<错误信息> static Gk8Str sg_iLoaderErrorStr; typedef size_t (*HTTPLOADERWRITE_CALLBACK)(GK8_LPVOID lpData,size_t nSize,size_t nMemBlock,GK8_LPVOID lpResponseData); #if (GK8_TARGET_PLATFORM==GK8_PLATFORM_IOS) #define GK8_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE 1 #else #define GK8_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE 0 #endif #if GK8_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE #define GK8_ASYNC_HTTPREQUEST_SEMAPHORE "Gk8HttpAsync" #else static sem_t sg_iLoaderSem; #endif GK8_INT ProcessLoaderTask(LPLOADERDATA pHttpLoaderResponse,HTTPLOADERWRITE_CALLBACK lpCallBack,GK8_LPINT lpResponseCode); //<接收HTTP下载数据> size_t WriteHttpLoaderData(GK8_LPVOID lpData,size_t nSize,size_t nMemBlock,GK8_LPVOID lpResponseData) { Gk8ByteMaker* pResponseData=(Gk8ByteMaker*)lpResponseData; size_t nLength=nSize*nMemBlock; pResponseData->WriteBuf(lpData,(GK8_INT)nLength); return nLength; } //<进度回调> size_t HandleLoaderProgress(GK8_LPVOID lpBuffer,GK8_DOUBLE dlTotal,GK8_DOUBLE dlNow,GK8_DOUBLE ulTotal,GK8_DOUBLE ulNow) { LPLOADERDATA pHttpLoaderResponse=(LPLOADERDATA)lpBuffer; Gk8HttpLoader* pHttpLoader=Gk8HttpLoader::GetInstance(); pHttpLoader->OnProgress(pHttpLoaderResponse,dlTotal,dlNow); return 0; } //<处理POST请求:流的行事发出> GK8_INT ProcessLoaderTask(LPLOADERDATA pHttpLoaderResponse,HTTPLOADERWRITE_CALLBACK lpWriteCallBack,GK8_LPINT lpResponseCode) { CURLcode nCurlCode=CURL_LAST; CURL* pCurl=curl_easy_init(); do { //远程URL,支持HTTP,HTTPS,FTP nCurlCode=curl_easy_setopt(pCurl,CURLOPT_URL,pHttpLoaderResponse->pLoaderUrl); if(nCurlCode!=CURLE_OK) break; //设置User-Agent Gk8Str iUserAgentStr="Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0.1"; nCurlCode=curl_easy_setopt(pCurl,CURLOPT_USERAGENT,iUserAgentStr); if(nCurlCode!=CURLE_OK) break; //设置重定向的最大次数 nCurlCode=curl_easy_setopt(pCurl,CURLOPT_MAXREDIRS,5); if(nCurlCode!=CURLE_OK) break; //设置301,302跳转跟随location nCurlCode=curl_easy_setopt(pCurl,CURLOPT_FOLLOWLOCATION,1); if(nCurlCode!=CURLE_OK) break; nCurlCode=curl_easy_setopt(pCurl,CURLOPT_NOSIGNAL,1L); if(nCurlCode!=CURLE_OK) break; nCurlCode=curl_easy_setopt(pCurl,CURLOPT_POST,false); if(nCurlCode!=CURLE_OK) break; //下载内容回调函数 nCurlCode=curl_easy_setopt(pCurl,CURLOPT_WRITEFUNCTION,lpWriteCallBack); if(nCurlCode!=CURLE_OK) break; nCurlCode=curl_easy_setopt(pCurl,CURLOPT_WRITEDATA,pHttpLoaderResponse->pFileBufData); if(nCurlCode!=CURLE_OK) break; //进度回调函数 nCurlCode=curl_easy_setopt(pCurl,CURLOPT_NOPROGRESS, 0); if(nCurlCode!=CURLE_OK) break; nCurlCode=curl_easy_setopt(pCurl,CURLOPT_PROGRESSDATA,pHttpLoaderResponse); if(nCurlCode!=CURLE_OK) break; nCurlCode=curl_easy_setopt(pCurl,CURLOPT_PROGRESSFUNCTION,HandleLoaderProgress); if(nCurlCode!=CURLE_OK) break; //跳过服务器SSL验证,不使用CA证书 nCurlCode=curl_easy_setopt(pCurl,CURLOPT_SSL_VERIFYPEER,0L); if(nCurlCode!=CURLE_OK) break; //验证服务器端发送的证书,默认是2(高),1(中),0(禁用) nCurlCode=curl_easy_setopt(pCurl,CURLOPT_SSL_VERIFYHOST,0L); if(nCurlCode!=CURLE_OK) break; nCurlCode=curl_easy_setopt(pCurl,CURLOPT_ERRORBUFFER,sg_szLoaderErrorBuf); if(nCurlCode!=CURLE_OK) return false; nCurlCode=curl_easy_perform(pCurl); if(nCurlCode!=CURLE_OK) break; nCurlCode=curl_easy_getinfo(pCurl,CURLINFO_RESPONSE_CODE,lpResponseCode); if(nCurlCode!=CURLE_OK||*lpResponseCode!=200) { nCurlCode=CURLE_HTTP_RETURNED_ERROR; } }while(0); if(pCurl) curl_easy_cleanup(pCurl); return (nCurlCode==CURLE_OK?0:1); } //<创建网络下载线程> static GK8_LPVOID LoaderNetWorkThread(GK8_LPVOID lpData) { LPLOADERDATA pHttpLoaderRequest=NULL; LPLOADERDATA pHttpLoaderResponse=NULL; while(true) { //Wait for http request tasks from main thread GK8_INT nSemWaitRet=sem_wait(sg_pLoaderSem); if(nSemWaitRet<0) { _GK8ERR<<"HttpRequest async thread semaphore error:"<<strerror(errno)<<CR; break; } if(sg_bHttpLoaderQuit) break; //<第一步:发送HTTP请求> pHttpLoaderRequest=NULL; pthread_mutex_lock(&sg_RequestLoaderMutex); if(0!=sg_iRequestLoaderQueue.GetSize()) { pHttpLoaderRequest=sg_iRequestLoaderQueue.GetItemAt(0); sg_iRequestLoaderQueue.RemoveItemAt(0); } pthread_mutex_unlock(&sg_RequestLoaderMutex); if(NULL==pHttpLoaderRequest) continue; //<清除二进制数据> pHttpLoaderRequest->pFileBufData->ClearStream(); //<第二步:libCurl同步请求> //pHttpLoaderResponse=new LOADERDATA(); //memcpy(pHttpLoaderResponse,pHttpLoaderRequest,sizeof(LOADERDATA)); pHttpLoaderResponse=pHttpLoaderRequest; GK8_INT nResponseCode=-1; GK8_INT nRetValue=0; nRetValue=ProcessLoaderTask(pHttpLoaderResponse,WriteHttpLoaderData,&nResponseCode); pHttpLoaderResponse->nResponseCode=nResponseCode; if(nRetValue!=0) { pHttpLoaderResponse->bSucceed=false; sg_iLoaderErrorStr=sg_szLoaderErrorBuf; pHttpLoaderResponse->sErrorBuffer=sg_iLoaderErrorStr; }else { pHttpLoaderResponse->bSucceed=true; } pthread_mutex_lock(&sg_ResponseLoaderMutex); sg_iResponseLoaderQueue.AddItem(pHttpLoaderResponse); pthread_mutex_unlock(&sg_ResponseLoaderMutex); } pthread_mutex_lock(&sg_RequestLoaderMutex); sg_iRequestLoaderQueue.Clear(); pthread_mutex_unlock(&sg_RequestLoaderMutex); if(sg_pLoaderSem!=NULL) { #if GK8_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE sem_unlink(GK8_ASYNC_HTTPREQUEST_SEMAPHORE); sem_close(sg_pLoaderSem); #else sem_destroy(sg_pLoaderSem); #endif sg_pLoaderSem=NULL; pthread_mutex_destroy(&sg_RequestLoaderMutex); pthread_mutex_destroy(&sg_ResponseLoaderMutex); //<依次删除数据> GK8_INT nIndex; for(nIndex=0;nIndex<sg_iRequestLoaderQueue.GetSize();nIndex++) { pHttpLoaderRequest=sg_iRequestLoaderQueue.GetItemAt(nIndex); delete pHttpLoaderRequest; } for(nIndex=0;nIndex<sg_iResponseLoaderQueue.GetSize();nIndex++) { pHttpLoaderResponse=sg_iResponseLoaderQueue.GetItemAt(nIndex); delete pHttpLoaderResponse; } sg_iRequestLoaderQueue.Destroy(); sg_iResponseLoaderQueue.Destroy(); } pthread_exit(NULL); return 0; } /////////////////////////////////////////////CLASS-TOSPP//////////////////////////////////////////////////// BEGIN_TOSPP_MAP(Gk8HttpLoader,Gk8BaseObj) TOSPP_FUNC(Gk8HttpLoader,AddLoaderFile,' ',"sssd","AddLoaderFile(lpFileName,lpLoaderUrl,lpLocalFile,nFileSize)") TOSPP_FUNC(Gk8HttpLoader,HttpLoaderFile,' ',"","HttpLoaderFile()") TOSPP_FUNC(Gk8HttpLoader,SetHttpLoad,' ',"d&v&v","SetHttpLoad(nLoadShowCase,iLoadProgressCallVar,iLoadFinishCallVar)") END_TOSPP_MAP() BEGIN_TOSPP_STATIC_FUN_MAP(Gk8HttpLoader) TOSPP_STATIC_FUNC(Gk8HttpLoader,GetInstance,'p',"","") END_TOSPP_STATIC_FUN_MAP ///////////////////////////////////////////////////////////////////////////////////////////////// Gk8HttpLoader::Gk8HttpLoader() { m_bLoading=false; m_nLoadShowCase=1; m_nLoadFileCount=0; m_nSumFileCount=0; m_nLoadFileSize=0; m_nSumFileSize=0; s_pLoaderCache=new Gk8BufEntry<LOADERDATA,256>; } Gk8HttpLoader::~Gk8HttpLoader() { sg_bHttpLoaderQuit=true; if(sg_pLoaderSem!=NULL) { sem_post(sg_pLoaderSem); } Destroy(); } //<初始化线程> GK8_BOOL Gk8HttpLoader::InitLoaderThreadSemphore() { if(sg_pLoaderSem!=NULL) { return true; }else { #if GK8_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE sg_pLoaderSem=sem_open(GK8_ASYNC_HTTPREQUEST_SEMAPHORE,O_CREAT,0644,0); if(sg_pLoaderSem==SEM_FAILED) { _GK8ERR<<"Open HttpLoader Semaphore Failed"<<CR; sg_pLoaderSem=NULL; return false; } #else GK8_INT nSemRet=sem_init(&sg_iLoaderSem,0,0); if(nSemRet<0) { _GK8ERR<<"Init HttpLoader Semaphore Failed"<<CR; return false; } sg_pLoaderSem=&sg_iLoaderSem; #endif pthread_mutex_init(&sg_RequestLoaderMutex,NULL); pthread_mutex_init(&sg_ResponseLoaderMutex,NULL); pthread_create(&sg_LoaderNetWorkThread,NULL,LoaderNetWorkThread,NULL); pthread_detach(sg_LoaderNetWorkThread); sg_bHttpLoaderQuit=false; } return true; } //<增加HTTP下载文件> GK8_VOID Gk8HttpLoader::AddLoaderFile(GK8_LPCSTR lpFileName,GK8_LPCSTR lpLoaderUrl,GK8_LPCSTR lpLocalFile,GK8_INT nFileSize) { GK8_UINT nNameId=Gk8OperSys::Str2UINT(lpFileName); LPLOADERDATA lpLoaderData=s_pLoaderCache->AddEntryWithNameId(nNameId); lpLoaderData->nNameId=nNameId; lpLoaderData->pFileName=lpFileName; lpLoaderData->pLoaderUrl=lpLoaderUrl; lpLoaderData->pLocalFile=lpLocalFile; lpLoaderData->nFileSize=nFileSize; lpLoaderData->pFileBufData=&m_iFileBufData; //<准备显示数据> m_nSumFileCount++; m_nSumFileSize+=nFileSize; m_iFileBufData.WriteAlloc(nFileSize); } GK8_VOID Gk8HttpLoader::SetHttpLoad(GK8_INT nLoadShowCase,Gk8Var& iLoadProgressCallVar,Gk8Var& iLoadFinishCallVar) { m_nLoadShowCase=nLoadShowCase; m_iLoadProgressCallVar=iLoadProgressCallVar; m_iLoadFinishCallVar=iLoadFinishCallVar; Gk8Var iEmptyVar; if(iLoadProgressCallVar.GetSize()==1 && iLoadProgressCallVar<0>.IfInt()) SetEvent(sg_iLoadProgressEvent,iLoadProgressCallVar<0>,iEmptyVar); if(iLoadFinishCallVar.GetSize()==1 && iLoadFinishCallVar<0>.IfInt()) SetEvent(sg_iLoadFinishEvent,iLoadFinishCallVar<0>,iEmptyVar); } //<开始HTTP下载文件> GK8_VOID Gk8HttpLoader::HttpLoaderFile() { //正在下载中 if(m_bLoading) return; if(s_pLoaderCache->GetBufNum()<1) { //<通知脚本下载完成> static Gk8Var sl_iParamVar; sl_iParamVar.RemoveAll(); if(m_iLoadFinishCallVar.GetSize()==1) { RunEventWithArgs(sg_iLoadFinishEvent,sl_iParamVar); }else { if(!m_iLoadFinishCallVar<0>.IfPtr()||!IfObjPtr(m_iLoadFinishCallVar<0>.GetPtr(),m_iLoadFinishCallVar<0>.GetPtrId())) return; Gk8Obj* pBindObj=m_iLoadFinishCallVar<0>.GetSafePtr(); pBindObj->OnCall(m_iLoadFinishCallVar<1>,sl_iParamVar); } m_nLoadFileCount=0; m_nSumFileCount=0; m_nLoadFileSize=0; m_nSumFileSize=0; return; } LPLOADERDATA lpLoaderData=s_pLoaderCache->GetBufEntryAt(0); if(false==InitLoaderThreadSemphore()) return; if(!lpLoaderData) return; m_bLoading=true; pthread_mutex_lock(&sg_RequestLoaderMutex); sg_iRequestLoaderQueue.AddItem(lpLoaderData); pthread_mutex_unlock(&sg_RequestLoaderMutex); sem_post(sg_pLoaderSem); } //<处理进度条> GK8_VOID Gk8HttpLoader::OnProgress(GK8_LPVOID lpLoaderData,GK8_CDOUBLE dlTotal,GK8_CDOUBLE dlNow) { LPLOADERDATA pLoaderData=(LPLOADERDATA)lpLoaderData; static Gk8Var sl_iParamVar; sl_iParamVar.RemoveAll(); sl_iParamVar<<m_nLoadShowCase<<pLoaderData->pFileName<<m_nLoadFileCount<<m_nSumFileCount <<(m_nLoadFileSize+(GK8_INT)dlNow)<<m_nSumFileSize<<(GK8_INT)dlTotal<<(GK8_INT)dlNow; if(m_iLoadProgressCallVar.GetSize()==1) { RunEventWithArgs(sg_iLoadProgressEvent,sl_iParamVar); }else { if(!m_iLoadProgressCallVar<0>.IfPtr()||!IfObjPtr(m_iLoadProgressCallVar<0>.GetPtr(),m_iLoadProgressCallVar<0>.GetPtrId())) return; Gk8Obj* pBindObj=m_iLoadProgressCallVar<0>.GetSafePtr(); pBindObj->OnCall(m_iLoadProgressCallVar<1>,sl_iParamVar); } } //<显示进度条> GK8_VOID Gk8HttpLoader::ShowLoadBar(GK8_LPVOID lpLoaderData) { LPLOADERDATA pLoaderData=(LPLOADERDATA)lpLoaderData; GK8_DOUBLE dlTotal=pLoaderData->nFileSize; GK8_DOUBLE dlNow=pLoaderData->nFileSize; OnProgress(lpLoaderData,dlTotal,dlNow); } //<获取HTTP下载器单例> Gk8HttpLoader* Gk8HttpLoader::GetInstance() { if(sg_pHttpLoader==NULL) sg_pHttpLoader=new Gk8HttpLoader(); return sg_pHttpLoader; } GK8_VOID Gk8HttpLoader::Destroy() { if(s_pLoaderCache!=NULL) { delete s_pLoaderCache; s_pLoaderCache=NULL; } } // GK8_VOID Gk8HttpLoader::HttpLoaderTick() { if(sg_pLoaderSem==NULL) return; LPLOADERDATA pLoaderData=NULL; pthread_mutex_lock(&sg_ResponseLoaderMutex); if(sg_iResponseLoaderQueue.GetSize()>0) { pLoaderData=sg_iResponseLoaderQueue.GetItemAt(0); sg_iResponseLoaderQueue.RemoveItemAt(0); } pthread_mutex_unlock(&sg_ResponseLoaderMutex); if(!pLoaderData) return; //<把服务器数据派遣到脚本中> Gk8Str iResponstStr; if(!pLoaderData->bSucceed) { _GK8ERR<<"Gk8HttpLoader Response Failed Error Is "<<pLoaderData->sErrorBuffer<<" nResponseCode:"<<pLoaderData->nResponseCode<<CR; iResponstStr="UnKown Error"; }else { //保存文件 Gk8File iFile; if(iFile.Open(pLoaderData->pLocalFile,Gk8File::modeWriteAbs)) { iFile.Write(pLoaderData->pFileBufData->GetBuf(),pLoaderData->pFileBufData->GetStreamSize()); iFile.Close(); } } m_nLoadFileCount++; ShowLoadBar(pLoaderData); m_nLoadFileSize+=pLoaderData->nFileSize; //移除已下载数据:继续下载 s_pLoaderCache->RemoveEntryWithNameId(pLoaderData->nNameId); m_bLoading=false; HttpLoaderFile(); }
标题:代号NSLG官网在哪下载 最新官方下载安装地址,
链接:https://www.miaoshengapp.cn/yxgl/131637.html
版权:文章转载自网络,如有侵权,请联系删除!
资讯推荐
热门手游
更多
热门攻略
-
代号NSLG官网在哪下载 最新官方下载安装地址, 2023-10-05
-
代号NSLG好玩吗 代号NSLG玩法简介, 2023-10-05
-
代号NSLG什么时候出 公测上线时间预告, 2023-10-05
-
代号MYXBJ什么时候出 公测上线时间预告, 2023-10-05
-
代号MJ官网在哪下载 最新官方下载安装地址, 2023-10-05
-
代号MJ好玩吗 代号MJ玩法简介, 2023-10-05
-
代号MJ什么时候出 公测上线时间预告, 2023-10-05
-
代号K好玩吗 代号K玩法简介,代号snk怎么玩 2023-10-05
-
代号eoe正版下载 代号eoe下载地址介绍, 2023-10-05
-
代号eoe官网预约 代号eoe官方地址介绍, 2023-10-05
热游排行榜