cocos2d-x curl로 Http, Ftp 파일 다운받기

 2012년 7월인지 8월에 마무리된 내용을 이제 정리해봅니다. 그 당시 cocos2d-x기반 프로젝트에서 패치 시스템을 만들라는 일정이 떨어지고 난 후 망연자실하고 있었더랬죠. 왜냐면 제가 하는일은 iOS와 안드로이드 다 돌아가는 프레임워크를 만드는게 제 일인데, 패치를 적용하려면 대체 어디서부터 어떻게 해야할지 난감했었죠. 뭐, 일반 PC 온라인 게임이었다면 고민도 안했겠지만요.

 그러던중 cocos2d-x에 샘플에 CurlTest라는 것이 있는 것을 확인을 했고 libcurl이라는 멋진녀석이 통합되어 있는것을 알게되었죠. 이것으로 하면 되겠다 싶어서 열심히 리서치해서 지금은 간단한 패치 툴과 iOS, Android다 잘되는 간단한 패치 시스템을 만들어 놓은 상태죠.

 보시다시피 샘플에 있는 CurlTest는 간단하게 웹을 콕 찍어보는 정도로만 구현이 되어있습니다. 이걸로는 파일 패치를 할 수없죠.

 이제부터 패치 전체말고, 간단하게 파일을 다운로드 받는 것만 정리해보겠습니다.

///< 파일포인터 구조체
typedef struct _StreamFile
{
 _StreamFile()
 {
  this->fpFile = 0;
 }
 ~_StreamFile()
 {
  if( this->fpFile )
   fclose( this->fpFile );
 
  this->fpFile = 0;
 }
 
 FILE* fpFile;
}StreamFile;
///< 파일 다운시 Curl로 부터 호출되어져 파일을 저장한다.
size_t PatchManager::fileWrite( void* buffer, size_t size, size_t nmemb, void* userData )
{
 StreamFile* pStream = ( StreamFile* )userData;
 if( pStream && !pStream->fpFile )
 {
  CCString strDownFile = PatchManager::sharedPatchManager()->getCurDownFile();
  pStream->fpFile = fopen( strDownFile.getCString(), "wb" );
 
  if( pStream->fpFile == 0 )
   return -1;
 }
 return fwrite( buffer, size, nmemb, pStream->fpFile );
}

{
...
///< curl 초기화
this->cURL = curl_easy_init();


///< 파일 받는 것 처리할 함수 등록.
curl_easy_setopt( cURL, CURLOPT_WRITEFUNCTION, &PatchManager::fileWrite );
...
startDownload( "localFile.xml", "serverFile.xml" );
...

}

int PatchManager::startDownload( CCString& strDownLocalFile, CCString& strServerFile )
{
 CURL* pCUrl = getCUrl();
 if( pCUrl == 0 )
  return CURLE_FAILED_INIT;
 ///< 다운받을 로컬 파일. cocos2d-x가 지원하는 getWriteablePath()에 해줘야 한다.
 this->strCurDownFile = CCString::createWithFormat( "%s%s", CCFileUtils::sharedFileUtils()->getWriteablePath().c_str(), strDownLocalFile.getCString() )->getCString();
  
 StreamFile streamFile;
 
 CCString* pServerFile = CCString::createWithFormat( "%s/%s/%s", getServerIp().getCString(), getServerRootDir().getCString(), strServerFile.getCString() );
 
 curl_easy_setopt( pCUrl, CURLOPT_URL, pServerFile->getCString() );
 curl_easy_setopt( pCUrl, CURLOPT_WRITEDATA, &streamFile );
 
 ///< 다운로드 시도!
 CURLcode res = curl_easy_perform( getCUrl() );
 CCLOG( "Try down - %s", pServerFile->getCString() );
 
 if( CURLE_OK != res)
 {
  CCLOG( "startDownload faile %d", res );
 }
 else
 {
  CCLOG( "startDownload OK", getCurDownFile().getCString() );
 }
 
 return res;
}

 중요한 것은 fileWrite함수와 startDownload 함수입니다. 크게 어려운부분은 없습니다. 또한 curl_easy_perform을 실행하게되면 curl이 Main Thread를 100% 다 사용하기 때문에 패치 진행률이라던지 UI적인 것을 갱신하려면 따로 Thread적으로 구현하셔야 합니다. 저는 아직 쓰레드까지 처리하진 않고 패치 모드에 Fake Thread Mode라고 만들어 놓고 팀원들과 사용중이죠.

 그리고 curl_easy_setopt를 통해 여러가지 Flag들을 지원하는 듯합니다. https 같은 보안 프로토콜 지원등도 있고 말이죠. 아마 위 소스로는 이같이 보안 프로토콜등은 접근이 안되 파일 다운로드 실패할 듯 하네요. 더 보완이 필요해보입니다. 자세한 것은 cURL 홈페이지를 참고하세요.

 마지막으로 안드로이드에서만 curl로 다운로드가 되지 않는다면, 아마도 저처럼 안드로이드 처음 접하신분들이 작업중이시라 그런 이슈에 직면했을 듯 합니다. CURLE_COULDNT_RESOLVE_HOST 에러가 발생할텐데 권한에 INTERNET을 추가해줘야합니다. 링크에 정리했으니 참고하세요.

댓글

  1. 잘봤습니다. 페이크 쓰레드를 사용중이시라고 하셨는데
    화면갱신이 잘되나요?

    답글삭제
    답글
    1. 흠.. 페이크 쓰레드가 오해의 소지가 있네요 ㅎ; 꼼수죠 뭐... 일단 화면 갱신은 잘됩니다.
      http://westwoodforever.blogspot.kr/2013/01/cocos2d-x-201-210-android-migration.html
      이 포스팅 뎃글 참고해보시면... 그냥 꼼수라는걸 아실꺼에요.. 절대 쓰레드가 아니에요 ㅎ;

      삭제

댓글 쓰기

이 블로그의 인기 게시물

라즈베리파이 라즈비안 한글 입력하기 - IBus

'xxx.exe' 프로그램을 시작할 수 없습니다. 지정된 파일을 찾을 수 없습니다.

라즈베리파이 라즈비안 한글 깨짐 수정하기