WinINet 과 WinHTTP 샘플

C++ 2011. 5. 3. 04:56

WinINet은 http, ftp 등 많은 지원을 하고 예전 버전부터 지원하고 있지만
서버 프로그램이나 윈도우 서비스 프로그램, 자주 웹 호출을 하는 경우엔 예상하기 힘든 오동작을 일으킬 수 있습니다.
(물론 재현은 어렵습니다. 그런데 문제 발생하면 골치 아파집니다.)

그래서 Http인 경우엔 WinHTTP 를 사용하도록 권장(msdn)되고 있습니다.
http://msdn.microsoft.com/en-us/library/aa382925(v=vs.85).aspx

그런데 하나의 프로젝트에서 WinINet과 WinHTTP를 동시에 구현하고 선택적으로 쓰고 싶은데 
#include <WinINet.h>와 #include <Winhttp.h>를 같이 인클루드하게 되면 충돌나서 문제가 발생합니다.

그래서 인터페이스 클래스를 만들고 이를 상속하여 각각 WinINet과 WinHTTP를 구현 클래스를 정의하고
.cpp 파일에서 WinINet.h와 WinHttp.h를 인클루드하게 하여 동시에 사용할 수 있습니다.

첨부파일은 이에대한 샘플입니다.

WinINet_WinHTTP.zip



샘플 설명
main 함수에 보면 다음과 같은 식으로 사용합니다.
(팩토리 메소드 등으로 선택적으로 객체 생성하여 사용하기 위함)

IWinInternetHelper* WinInternetHelper = NULL;

//WinInternetHelper = new CWinHTTPHelper(); // WinHTTP 사용시
WinInternetHelper = new CWinINetHelper(); // WinINet 사용시

tstring URL = _T("http://www.naver.com");
tstring response = _T("");
WinInternetHelper->Query(URL, response);


보통 웹페이지가 UTF-8 no BOM 형식으로 되어있는것 같아서
UTF8Conv.h(http://kilojuliet.tistory.com/36) 를 사용하여 UTF-8에서 char나 wchar로 변환하고 있습니다.

프로젝트는 MBCS, UNICODE 지원
동기식 (비동기는 고려되지 않음)
또한 세션과 커넥션 핸들은 한번 연결 후 재활용

에러 발생시 재연결





WinINet FTP 파일 업로드 & 다운로드


출처 : http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=8143&ref=8143


FTP를 사용 할수 있게 처음 설정 하는부분과

 

FTP에 파일을 Upload 한후

 

FTP에 Upload 한 파일을 다시 Download 한후

 

FTP에 Upload 한 파일을 Delete 하는

 

간단한 예제 입니다.

 

장황한 설명보다는 간단하게 만들어 놓은 예제가 공부하기 쉬울거 같아 몇자 글적여 봅니다. ^^

 

함수 각각의 옵션이나 설명은 MSDN을 참조하세요 ^^

 



// FTP Open
HINTERNET m_hOpen = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, NULL);
if(NULL == m_hOpen) 
{
 AfxMessageBox("Open Error");
 return;
}

 

HINTERNET m_hConnect = InternetConnect(m_hOpen, 
                                       "100.100.100.1", 
                                       INTERNET_DEFAULT_FTP_PORT, 
                                       "USER_ID", 
                                       "USER_PASSWORD", 
                                       INTERNET_SERVICE_FTP, 
                                       0, 0);
if(NULL == m_hConnect)
{
 AfxMessageBox("Connect Error");
 InternetCloseHandle(m_hOpen);
 return;
}
// FTP Open End

 


 

// FTP Set Current Directory
if(!FtpSetCurrentDirectory(m_hConnect, "/DirName"))
{
 AfxMessageBox("Set Current Directory Error");
 InternetCloseHandle(m_hConnect);
 InternetCloseHandle(m_hOpen);
 return;
}
// FTP Set Current Directory

 



// FTP Upload ( C:\Test.Dat 파일을 FTP의 Set Current Directory 한 곳에 Test.Dat 이름으로 Upload 함 )
if(!FtpPutFile(m_hConnect, "C:\\Test.Dat", "Test.Dat", INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_RELOAD, 0))
{
 AfxMessageBox("FTP Upload Error");
 InternetCloseHandle(m_hConnect);
 InternetCloseHandle(m_hOpen);
 return;
}
// FTP Upload End

 


 

// FTP Download ( FTP의 Set Current Directory 한 곳에 Test.Dat 파일을 C:\Test.Dat 이름으로 Download 함 )
if(!FtpGetFile(m_hConnect, "C:\\Test.Dat", "Test.Dat", FALSE , NULL, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_RELOAD, 0))
{
 AfxMessageBox("FTP Download Error");
 InternetCloseHandle(m_hConnect);
 InternetCloseHandle(m_hOpen);
 return;
}
// FTP Download End

 


 

// FTP Delete ( FTP의 Set Current Directory 한 곳에 Test.Dat 파일을 삭제함 )
if(!FtpDeleteFile(m_hConnect, "Test.Dat"))
{
 AfxMessageBox("FTP Delete Error");
 InternetCloseHandle(m_hConnect);
 InternetCloseHandle(m_hOpen);
 return;
}

// FTP Delete End

 


 

// FTP Close
if(m_hOpen) 
{
 InternetCloseHandle(m_hOpen);
 m_hOpen = NULL;
}


if(m_hConnect) 
{
 InternetCloseHandle(m_hConnect);
 m_hConnect = NULL;
}
// FTP Close End









WinHttp 이어받기 (다운로드)


HTTP 1.1 이상에서 지원하며 헤더에 Range를 통해 원하는 바이트 만큼 가져옴.

아래는 0부터 9까지 10개의 byte를 요청함.

0- 로 하면 0부터 끝까지를 의미.


WinHttpOpenRequest(...)


//range : http code가 206으로 옴

if (!WinHttpAddRequestHeaders(

reqs_,

L"Range:bytes=0-9",

(ULONG)-1L,

WINHTTP_ADDREQ_FLAG_ADD))

{

error_ = getLastError();

return false;

}


WinHttpSendRequest(...)