본문 바로가기

코드^학습/메모한 지식

[C++] InternetReadFile API로 파일 다운로드

최근에는 간단한 툴 제작으로 파일을 다운받을 필요가 있었습니다.

그런데 생각해보니 저는 네트워크 쪽 개발은 리눅스에서(학생시절에)만 한번 해본게 생각났습니다.

리눅스 소켓을 열고 바인드하고 서버에 연결이 되면 파일크기를 받아와서 패킷의 크기를 정해두고 받아오는...그런 프로그램을 한번 만들어 봤습니다.


네트워크 코딩하라고 할때 윈도우쪽으로 가서 열심히 해두면...좀 더 자신감이 있었을지는 모르겠습니다만... 그 당시에는 리눅스 쪽이 MFC를 안 쓰고 네트워크 통신에만 집중할 수 있어서

좀더 쉬운쪽으로 수업을 들었던 것같습니다.


제가 필요한 내용은 주소(IP or URL)을 알고 있는 상태에서 해당 위치의 파일을 다운받아 오면 되는 그런 간단한 동작이었기 때문에

혹시나 소켓을 제가 정의하지 않고도 바로 쓸 수 있는 함수가 없을까 찾아보기 시작했습니다.

그래서 구글검색을 통해 알아낸 함수가 바로 InternetReadFile입니다. File접근 함수랑 비슷한 형식에 URL이 필요한 형태인게 사용하기가 아주 간편해서 좋았습니다.


이 함수를 제가 만든 코드와 함께 더 살펴보겠습니다.

(저는 유니코드 프로젝트를 기본으로 설정하여 작업하고 있습니다.)


CString strReturn = _T("");

HINTERNET hInternet = InternetOpen(_T("OpenName AMouGerNa"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);


HINTERNET hOpenUrl = InternetOpenUrl(hInternet, strURL, NULL, 0, INTERNET_FLAG_RELOAD, 0);


DWORD dwReadAvailable = 0;

InternetQueryDataAvailable(hOpenUrl, &dwReadAvailable, 0, 0); //서버가 바로 보낼 수 있는 데이터의 양 확인


char szReadBuffer[MAX_PATH] = {0, }; //읽을 버퍼

DWORD dwReadedByte = 0; // 읽어온 값 크기

if ( TRUE == InternetReadFile(hOpenUrl, szReadBuffer, dwReadAvailable, &dwReadedByte) )

{

//읽어온 값이 UTF-8이므로 변환하여 정상적인 텍스트를 얻기

int nLen = MultiByteToWideChar(CP_UTF8, 0, szReadBuffer, dwReadedByte, NULL, NULL);

TCHAR szTrans[MAX_PATH] = {0, };

MultiByteToWideChar(CP_UTF8, 0, szReadBuffer, dwReadedByte, szTrans, nLen);


strReturn.Format(_T("%s"), szTrans);

}


InternetCloseHandle(hOpenUrl);

InternetCloseHandle(hInternet);


파일을 읽어오기 위해서 InternetOpen이란 함수를 사용합니다.

첫번째 들어가는 인자는 Open이름인데 아무거나 쓰셔도 됩니다.

두번째 인자는 PRECONFIG, DIRECT, PROXY, PRECONFIG_WITH_NO_AUTOPROXY 4종류 인데... AccessType입니다.

자세한건 MSDN에서....

세번째 인자는 PROXY를 써야 넣는 부분이니까 PASS,

네번째 인자도 마찬가지로 PASS

다섯번째 인자는 flag인데 이 부분도 자세히는 모르겠네요. 어쨋든 0을 넣습니다.


자 InternetOpen이 성공하면 핸들을 넘겨줍니다. 이 핸들은 InternetOpenUrl에 첫번째 인자로 쓰이구요.

두번째엔 URL을

세번째 인자는 HTTP서버에 보내는 특정한 헤더? 인가본데 지금은 필요하지 않은것 같습니다 NULL

나머지는 비슷하게 따라쓰다가 INTERNET_FLAG_RELOAD 이게 무슨 내용인가 했는데 [Forces a download of the requested file, object, or directory listing from the origin server, not from the cache.] MSDN에 이렇게 나옵니다.

강제로 파일,객체,디렉토리 등을 다운받도록 요청하는 건가봅니다.


여기까지 성공했다면 역시 핸들을 넘겨줍니다. 이게 InternetReadFile의 첫번째 인자에 들어가죠.

이제 드디어 InternetReadFile을 사용할 수 있게 됐습니다.(음 뭔가 긴 여정이었어)

첫번째 인자에는 InternetOpenUrl이나 FtpOpenFile, HttpOpenRequest 셋중 하나가 리턴한 핸들을 넣어주면 됩니다.

작업중인 부분에 맞게 적어주시면 되요.

두번째 인자는 읽어올 데이터가 저장될 버퍼의 주소

세번째 인자는 서버가 한번에 보내줄 수 있는 양인데 InternetQueryDataAvailable 이걸로 알아오면 됩니다.

네번째 인자는 실제로 받아들인 데이터의 크기를 담을 DWORD 변수 주소를 넘겨주면


자 근데 파일이 작은 크기가 아니라면 이렇게 한번만 해선 안 되겠죠?

저 과정중에 InternetReadFile을 반복하시면 됩니다. InternetQueryDataAvailable를 포함해서요.


즐거운 코딩되세요 


제가 참고한 출처입니다.

[출처 : http://m.blog.daum.net/alwaysnr/6]

[출처 : https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa385103(v=vs.85).aspx]


다음블로그를 통해서 가장먼저 발견했는데 필요한 내용이 쉽게 설명되어 있습니다.