WinInet API
WinInet(The Microsoft Win32 Internet functions) 클래스는 Win32반의 WinInet API들을 캡슐화하고 있는 클래스의 모임을 말하며 클라이언트 쪽에서 인터넷의 표준 프로토콜인 HTTP, Gopher, FTP 등을 지원하기 위한 클래스이다. MFC에서 제공하는 WinInet 관련 클래스들은 네트워크상에서 발생하는 여러 가지 복잡한 처리 작업을 내부적으로 수행하고 상당히 안정적인 코드를 제공한다. 이러한 프로토콜을 사용한 전송을 쉽게 할 수 있도록 운영체제 확장의 일부로 wininet.dll을 제공한다. MFC 응용 프로그램에서 wininet.dll은 CInternetSession 개체에 의해 표현된다. CInternetSession은 작업자가 인터넷에 정확히 어떻게 연결하려고 했는지 wininet.dll에게 알리도록 한다.
CInternetSession(LPCTSTR pstrAgent = NULL, DWORD dwContext = 1, DWORD dwAccessType = RNET_OPEN_TYPE_PRECONFIG, LPCTSTR pstrProxyName = NULL, LPCTSTR pstrProxyBypass = NULL, DWORD dwFlags = 0);
첫 번째 인자는 클라이언트 쪽 소프트웨어 이름을 가리키는 포인터이다. 디폴트값 NULL은 생성자가 AfxGetAppName() 호출을 통해 응용프로그램의 이름을 찾게 할 것이다. dwAccessType 인자는 WinInet에게 인터넷을 어떻게 연결할 계획인지 알려준다. 디폴트 값인 INTER_OPEN_TYPE_PRECONFIG는 레지스트리에서 인터넷 연결에 관하여 이전에 입력된 정보를 찾는다. 인트라넷을 사용하고 있거나 컴퓨터가 인터넷에 직접 연결되어 있다면 INTERNET_OPEN_TYPE_DIRECT를 지정할 수 있다. 방화벽을 통한 연결은 GATEWAY_INTERNET_ACCESS, 프록시를 통해 인터넷에 요청을 전달하려고 하려면 INTERNET_OPEN_TYPE_PROXY를 지정한다. 이것을 지정하지 않으면 pstrProxyName과 pstrProxyBypass 인자를 NULL로 지정할 수 있다. 그리고 dwFlags 인자를 사용하여 다른 방법으로 연결에 영항을 줄 수 있다. 비동기 동작을 지원하는 INTERNET_FLAG_ASYNC 플래그와 세션을 통해 기존 연결을 재사용하려는 INTER_FLAG_EXITING_CONNECT 플래그가 OR 연산자를 사용하여 결합된다.
dwContext라는 인자가 있는데 인터넷에 있는 다른 컴퓨터와 대화하는 것은 오랜 시간이 걸릴 수 있다. 일부 프로토콜 등은 많은 오버헤드를 발생시키고, 인터넷 응용 프로그램의 사용자들은 종종 느린 링크를 통해서 연결된다. 따라서 윈도우 인터넷 API는 언제, 어떤 것이 진행되었는지 응용프로그램이 알 수 있게 하는 콜백을 제공한다. dwContext 인자는 단순히 응용 프로그램이 실행하고 있는 각 동작들을 구분할 수 있게 해준다. MFC는 콜백 함수처럼 복잡한 것들에 대해 염려하지 않아도 되게 해준다. CInternetSession으로부터 클래스를 유도하고 OnStatusCallback() 함수를 오버라이드할 수 있다.
또 CInternetSession 듀도 개체에 EnableStatusCallback() 함수를 호출하여 상태 콜백을 받고 싶어한다는 것을 시스템에게 알릴 필요가 있다. 이 인자가 TRUE(디폴트)이면 함수가 콜백을 활성화시킬 것이고, FALSE이면 인자가 콜백을 비활성화시킬 것이다. CInternetSession을 열고 FTP 프로토콜을 이용하여 파일을 전송할 경우 GetFtpConnection() 멤버를 호출함으로써 FtpConnection 개체를 생성할 수 있다. GetFtpConnection()은 이 새 CFtpConnection을 가리키는 포인터를 반환한다.
CFtpConnection* GetFtpConnection( LPCTSTR pstrServer, LPCTSTR pstrUserName = NULL, LPCTSTR pstrPassword = NULL, INTERNET_PORT nPort = INTERNET_INVALID_PORT_NUMBER, BOOL bPassive = FALSE );
첫 번째 인자는 연결하고자 하는 서버의 이름이고 두 번째 인자와 세 번째 인자는 연결에 사용될 사용자 이름과 암호를 나타낸다. 디폴트 값인 NULL을 전달하면 익명(anonynous)으로 접속요청을 하게 된다. nPort 인자는 포트 번호를 나타내는데 디폴트 값인 INTERNET_INVALID_PORT_NUMBER을 사용하면 이 프로토콜의 디폴트 TCP/IP 포트 번호(HTTP:80, FTP:21, Gopher:70, HTTPS:443)를 사용한다. 이를 이용한 FTP 서버 접속은 리스트 3과 같다.
리스트 3 : FTP 서버 접속
------------------------------------------------------------
CInternetSession m_Session;
CFtpConnection *m_pConnection = NULL;
try
{
//Anonymous 로 로그인
m_pConnection = m_Session.GetFtpConnection(ftp.pserang.co.kr);
// 사용자명과 패스워드 로그인
/* m_pConnnection = m_Session.GetFtpConnection(ftp.pserang.co.kr","User_Name","Password); */
//연결시 작업
m_pConnection->Close();
}
catch (CInternetException *m_pEx)
{
m_pEx->ReportError(MB_ICONEXCLAMATION);
m_pConnection = NULL;
m_pEx->Delete();
}
delete m_pConnection;
------------------------------------------------------------
CInternetException은 운영체제로부터 문제를 기술하는 에러 텍스트를 얻어내는 에외처리 클래스이다. 연결이 이루어 졌을 때 GetCurrentDirectory()를 호출하여 FTP 컴퓨터의 현재 디렉토리를 얻을 수 있고 SetCurrentDirectory()로 상대편 디렉토리를 설정할 수 있다. 그리고 GetFile()로 파일을 다운로드 할 수 있고 PutFile()로 파일을 업로드 할 수 있다. 사용자에게 권한이 주어지면 CreateDirectory()/RemoveDirectory() 및 Remove()/Rename()를 호출하여 디렉토리를 생성/추가할 수 있고 파일을 제거/이름변경을 할 수 있다. 예를 들어 파일을 다운로드 할 때의 코드는 다음과 같다.
m_pConnection->GetFile("RemoteFile", "localFile", FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE);
네 번째 인자(DWORD dwAttributes)는 파일 복사 후 로컬 컴퓨터에 생성되는 파일의 속성을 나타낸다. 읽기 전용은 FILE_ATTRIBUTE_READONLY로 지정할 수 있다. 다섯 번째 인자(DWORD dwFlags)는 원시 이진 파일들을 처리할 수 없는 연결을 통해 올바로 데이터를 전달하기 위해 FTP 프로토콜에 사용되는 의미를 바꾼다. CFtpFileFind란 클래스가 있는데 FTP 서버를 검색하는 기능을 수행한다. 이 클래스는 CFileFind 클래스에서 파생되었다. CFtpFileFind 클래스는 두 개의 인자가 있는데 첫 번째 인자는 검색할 서버를 위한 CFtpConnectiondmf 가리키는 포인터이고 두 번째 인자는 dwContext 값을 나타낸다.
CFtpFileFind *m_pFileFind = NULL;
m_pFileFind = new CFtpFileFind(m_pConnection);
BOOL bContinue = TRUE;
CString m_file_name;
m_pFileFind->FindFile("RemoteDir");
while(bContinue)
{
bContinue = m_pFileFind->FindNextFile();
m_file_name = m_pFileFind->GetFileName();
if(m_pFileFind->IsDirectory())
{
//디렉토리일 경우 루틴
}
// 파일인 경우
else
{
//파일일 경우 루틴
}
}
FTP 서버로 연결이 되면 CFtpFileFind 클래스를 이용하여 지정된 경로의 파일을 계속 찾는 구문이다. HTTP 서버 즉, 일반적으로 말하는 웹 서버에 접속하기 위해서 MFC 계층에서 CFtpConnection과 비슷한 위치를 차지하는 CHttpConnection를 사용해 연결할 수 있다. CInternetSession의 GetHtpConnection() 멤버를 사용하여 CHttpConnection을 열 수 있다.
CHttpConnection* GetHttpConnection( LPCTSTR pstrServer, INTERNET_PORT nPort = NTERNET_INVALID_PORT_NUMBER, LPCTSTR pstrUserName = NULL, LPCTSTR pstrPassword = NULL );
각 인자는 GetFtpConnection()과 거의 동일하다. 웹서버에 접속하는 코드는 다음과 같다.
CInternetSession m_Session;
CHttpConnection *m_pHttpConnection = NULL;
CHttpFile *m_pFile = NULL;
try
{
m_pHttpConnection = m_Session.GetHttpConnection(www.pserang.co.kr);
m_pFile = m_pHttpconnection->OpenRequest(CHttpConnection::HTTP_VERB_GET,"/");
m_pFile -> AddRequestHeaders("Accept:text/*\r\nAccept-Language:kr\r\n");
m_pFile ->SendRequest();
//...
}
catch(CInternetException *m_pEx)
{
m_pEx->ReprotError();
m_pEx->Delete();
}
delete m_pFile;
delete m_pHttpConnection;
CHttpFile이라는 것이 있는데 CInternetFile로부터 유도되었고 CInternetFile은 CStdioFile로부터 유도되었다. CHttpFile의 특징은 자신만의 파일 데이터 버퍼링을 수행한다. SetReadBufferSize()를 호출하여 버퍼 크기를 설정할 수 있고, 버퍼를 설정하지 않고서 ReadString()을 사용하면 자동으로 버퍼가 설정된다. 위 코드 중 서버에게 요청하는 OpenRequest()의 첫 번째 인자는 CHttpConnection 내부의 enum에서 정의된 기호이다. 이 인자는 요청에서 사용하고자 하는 메소드를 지정한다. HTTP_VERB_GET이라는 메소드는 서버에 있는 개체의 전체 내용을 요청하는데 쓰인다. 그 외 특정 개체와 연결된 개체를 전달하고자 할 때는 HTTP_VERB_POST 인자가 쓰이고 마지막 인자인 POST 대신 HEAD, PUT, LINK, DELETE, UNLINK 등이 사용된다. 요청은 CHttpFile::SendRequest() 호출과 함께 전달된다. 요청을 전달하기 전에 헤더를 추가하고 싶으면 CHttpFile::AddHeaders()를 호출할 수 있다. 서버가 요청에 대한 개체를 갖고 있지만 클라이언트의 Accept: 헤더에서 지정된 형식 요청을 충족시킬 수 없으면 일반 "404 Not Found"(HTTP_STATUS_NOT_FUOND: 404)" 에러와
"HTTP_STATUS_NONE_ACCEPTABLE: 406" 에러를 반환할 것이다. 요청이 전달되고 반응이 성공적으로 수신되었으면 SendRequest()가 TRUE를 반환한다. 그렇지 않으면 예외가 발생할 것이다. 이것은 내부 서버 에러가 있다는 것을 의미한다. CHttpFile::QueryInfoStatusCode()를 호출함으로써 CHttpFile 개체로 들어온 정보로부터 반환 코드를 커낼 수 있다.
m_pFile->SendRequest();
DWORD m_dwStatusCode;
m_pFile->QueryInfoStatusCode(m_dwStatusCode);
m_dwStatusCode는 요청 결과에 반영하는 정수를 갖고 있다. 예를 들어 200은 HTTP_STATUS_OK를 나타내며 요청이 게이트웨이로 갔지만 게이트웨이와 서버와의 통신이 타임아웃일 경우는 504(HTTP_STATUS_GATEWAY_TIMEOUT)를 나타낸다
리스트 4는 프록시를 통하여 HTTP 파일을 다운로드 하는 코드이다.
'Programming' 카테고리의 다른 글
search folder or read folder (0) | 2010.01.29 |
---|---|
프로세스 검색 코드 (0) | 2010.01.26 |
변환 : CString -> LPTSTR (0) | 2010.01.26 |