2014년 10월 27일 월요일

서버에 있는 파일을 읽어서, 1초 단위로 PC에 저장.

int WINAPI _DownloadServerFile( IN HANDLE hFile, IN DWORD dwFileServerSize, IN LPCTSTR pszURL, IN BOOL isFileExist )
{
 HINTERNET   hInternet = NULL;
 HINTERNET   hConnect = NULL;
 HINTERNET   hRequest = NULL;
 int     result;
 DWORD    dwSize, dwRead, dwWritten, dwTotalWrittenBytes;
 LPBYTE    pbBuffer = NULL, pbTemp = NULL;
 DWORD    dwBufferSize, dwNewSize;
 int     nStatusCode;
 int     nBufferPos;
 clock_t    lStartClock, lEndClock, lDuration;
 BYTE    baHeader[ 128 ];
 URL_COMPONENTS  stURLComponents;
 TCHAR    szSchemeName[ INTERNET_MAX_SCHEME_LENGTH ];
 TCHAR    szHostName[ INTERNET_MAX_HOST_NAME_LENGTH ];
 TCHAR    szUserName[ INTERNET_MAX_USER_NAME_LENGTH ];
 TCHAR    szPassword[ INTERNET_MAX_PASSWORD_LENGTH ];
 TCHAR    szURLPath[ INTERNET_MAX_URL_LENGTH ];
 DWORD    dwServiceType, dwFlag;
 TCHAR    szEncodedURL[ 4096 ];
 TCHAR    szHeader[ 1024 ];
 DWORD    dwFileSize, dwCurrentPos, dwStartBytes;

 //------------------------------------------------------------------------
 //
 // URL 파싱
 //
 //------------------------------------------------------------------------
 ZeroMemory( &stURLComponents, sizeof( URL_COMPONENTS ) );

 stURLComponents.dwStructSize = sizeof( URL_COMPONENTS );
 stURLComponents.lpszScheme = szSchemeName;
 stURLComponents.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH;
 stURLComponents.lpszHostName = szHostName;
 stURLComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
 stURLComponents.lpszUserName = szUserName;
 stURLComponents.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH;
 stURLComponents.lpszPassword = szPassword;
 stURLComponents.dwPasswordLength = INTERNET_MAX_PASSWORD_LENGTH;
 stURLComponents.lpszUrlPath = szURLPath;
 stURLComponents.dwUrlPathLength = INTERNET_MAX_URL_LENGTH;

 ::URLEncode( pszURL, szEncodedURL, 4096 );
 result = InternetCrackUrl( szEncodedURL, _tcslen( szEncodedURL ), 0, &stURLComponents );
 if( result == FALSE )
 {
  DEBUGINFO( _T( "pszPreURL = %s" ), pszURL );
  result = ERRORMSG( GetLastError(), _T( "Can not parse URL" ) );
  STACKTRACE( _T( "InternetCrackUrl()" ) );
  goto finish;
 }

 hInternet = InternetOpen( _T( "libAPI" ), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
 if( hInternet == NULL )
 {
  result = ERRORMSG( GetLastError(), _T( "Can not open internet session" ) );
  STACKTRACE( _T( "InternetOpen()" ) );
  goto finish;
 }

 dwFlag = INTERNET_FLAG_DONT_CACHE;
 switch( stURLComponents.nScheme )
 {
 case INTERNET_SERVICE_HTTP:
  dwServiceType = INTERNET_SERVICE_HTTP;
  break;
 
 case INTERNET_SCHEME_FTP:
  dwServiceType = INTERNET_SERVICE_FTP;
  break;
 
 case INTERNET_SCHEME_GOPHER:
  dwServiceType = INTERNET_SERVICE_GOPHER;
  break;
 
 case INTERNET_SCHEME_HTTPS:
  dwServiceType = INTERNET_SERVICE_HTTP;
  dwFlag |= INTERNET_FLAG_SECURE;
  break;
 
 default:
  dwServiceType = INTERNET_SERVICE_HTTP;
  break;
 }

 //------------------------------------------------------------------------
 //
 // 파일이 이미 존재하고 이어받기를 선택한 경우
 //
 //------------------------------------------------------------------------
 dwStartBytes = 0;
 if( ( isFileExist == TRUE ) && ( m_nWriteOption == NCG_WRITE_CONTINUE ) )
 {
  dwCurrentPos = SetFilePointer( m_hFileHandle, 0, 0, FILE_CURRENT );
  dwFileSize = GetFileSize( m_hFileHandle, NULL );
  dwStartBytes = dwFileSize - dwCurrentPos;

  if( dwStartBytes >= dwFileServerSize )
  {
   OnTransfer( dwFileServerSize, dwFileServerSize );
   OnEnd( 0 );
   result = 0;
   goto finish;
  }
  else
  {
   _stprintf( szHeader, _T( "Range: bytes=%d-" ), dwStartBytes );
   SetFilePointer( m_hFileHandle, 0, 0, FILE_END );
  }
 }
 else
 {
  szHeader[ 0 ] = 0;
 }

 hConnect = InternetConnect( hInternet,
        szHostName,
        stURLComponents.nPort,
        NULL,
        NULL,
        dwServiceType,
        dwFlag,
        NULL );

 if( hConnect == NULL )
 {
  result = ERRORMSG( GetLastError(), _T( "Can not connect host" ) );
  STACKTRACE( _T( "InternetOpenUrl()" ) );
  goto finish;
 }

 hRequest = HttpOpenRequest( hConnect, _T( "GET" ), stURLComponents.lpszUrlPath, NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, NULL );
 if( hRequest == NULL )
 {
  goto finish;
 }

 //------------------------------------------------------------------------
 //
 // 웹서버에 데이타를 전송
 //
 //------------------------------------------------------------------------
 result = HttpSendRequest( hRequest, szHeader, _tcslen( szHeader ), 0, 0 );
 if( result == FALSE )
 {
  result = ERRORMSG( GetLastError(), _T( "Can not request URL" ) );
  STACKTRACE( _T( "HttpSendRequest()" ) );
  goto finish;
 }

 dwSize = sizeof( baHeader );
 result = HttpQueryInfo( hRequest, HTTP_QUERY_STATUS_CODE, baHeader, &dwSize, NULL );
 if( result == FALSE )
 {
  result = ERRORMSG( GetLastError(), _T( "HTTP 헤더로부터 상태 코드를 가져올 수 없습니다" ) );
  STACKTRACE( _T( "HttpQueryInfo()" ) );
  goto finish;
 }

 nStatusCode = _ttoi( (LPCTSTR)baHeader );
 if( nStatusCode == 404 )
 {
  //
  // 못찾았다
  // 그냥 스킵
  //
  result = ERRORMSG( ERROR_NOT_FOUND, _T( "%s URL에 파일이 존재하지 않습니다" ), pszURL );
  goto finish;
 }
 else if( ( nStatusCode != 200 ) && ( nStatusCode != 304 ) && ( nStatusCode != 206 ) )
 {
  result = ERRORMSG( ERROR_HTTP_INVALID_QUERY_REQUEST,
   _T( "%d is invalid response from web server" ), nStatusCode );
  goto finish;
 }

 dwTotalWrittenBytes = 0;
 nBufferPos = 0;

 //------------------------------------------------------------------------
 //
 // 초기 버퍼 크기를 10K byte 로 잡는다.
 //
 //------------------------------------------------------------------------
 dwBufferSize = 10240;
 pbBuffer = new BYTE[ dwBufferSize ];
 if( pbBuffer == NULL )
 {
  result = ERRORMSG( ERROR_NOT_ENOUGH_MEMORY, NULL );
  DEBUGINFO( _T( "dwBufferSize = %d" ), dwBufferSize );
  goto finish;
 }

 lStartClock = clock();

 if( dwStartBytes != 0 )
 {
  dwWritten = dwTotalWrittenBytes = dwStartBytes;
  OnTransfer( dwWritten, dwTotalWrittenBytes );
 }

 do
 {
  if( m_bDownloadCancel == TRUE )
  {
   TRACE( _T( "User canceled downloading. so return" ) );
   result = ERROR_CANCELLED;
   goto finish;
  }
 
  result = InternetQueryDataAvailable( hRequest, &dwSize, 0, 0 );
  IF_TRUE_GOTO( result == FALSE, GetLastError() );
 
  if( nBufferPos + dwSize > dwBufferSize )
  {
   //------------------------------------------------------------------------
   //
   // 1초가 안되었는데 버퍼가 풀이다
   //
   //------------------------------------------------------------------------
   dwNewSize = dwBufferSize + dwSize;
   pbTemp = new BYTE[ dwNewSize ];
   if( pbTemp == NULL )
   {
    result = ERRORMSG( ERROR_NOT_ENOUGH_MEMORY, NULL );
    DEBUGINFO( _T( "dwBufferSize = %d" ), dwNewSize );
    goto finish;
   }
 
   CopyMemory( pbTemp, pbBuffer, dwBufferSize );
   dwBufferSize = dwNewSize;
 
   delete[] pbBuffer;
   pbBuffer = pbTemp;
  }
 
  result = InternetReadFile( hRequest, &pbBuffer[ nBufferPos ], dwSize, &dwRead );
  IF_TRUE_GOTO( result == FALSE, GetLastError() );
 
  nBufferPos += dwRead;
  if( dwRead == 0 )
  {
   break;
  }
 
  lEndClock = clock();
  lDuration = ( lEndClock - lStartClock ) / CLOCKS_PER_SEC;
 
  //------------------------------------------------------------------------
  //
  // 버퍼를 다 채우지 못하고 1초가 넘었다. 파일에 쓴다
  //
  //------------------------------------------------------------------------
  if( lDuration >= 1 )
  {
   result = WriteFile( hFile, pbBuffer, nBufferPos, &dwWritten, NULL );
   IF_TRUE_GOTO( result == FALSE, GetLastError() );
 
   nBufferPos = 0;
   dwTotalWrittenBytes += dwWritten;
   lStartClock = clock();
 
   OnTransfer( dwWritten, dwTotalWrittenBytes );
  }
 } while( dwRead != 0 );

 //------------------------------------------------------------------------
 //
 // 아직 파일에 쓰지 못한 여분이 남아 있다면 파일에 쓰고 종료
 //
 //------------------------------------------------------------------------
 if( nBufferPos != 0 )
 {
  result = WriteFile( hFile, pbBuffer, nBufferPos, &dwWritten, NULL );
  IF_TRUE_GOTO( result == FALSE, GetLastError() );
 
  dwTotalWrittenBytes += dwWritten;
 
  OnTransfer( dwWritten, dwTotalWrittenBytes );
 }

 result = 0;

finish:
 if( result != 0 )
 {
  STACKTRACE( _T( "_DownloadServerFile" ) );
 }

 if( hRequest != NULL )
 {
  InternetCloseHandle( hRequest );
 }

 if( hConnect != NULL )
 {
  InternetCloseHandle( hConnect );
 }

 if( hInternet != NULL )
 {
  InternetCloseHandle( hInternet );
 }

 if( pbBuffer != NULL )
 {
  delete[] pbBuffer;
 }

 return result;
}


//OnTransfer OnEnd OnBegin은 프로그레스바 및 상태를 나타내기 위한 인터페이스 함수이다.

댓글 없음: