[Visual C++] 서울시 열린데이터 광장 Open API 이용하기 – 2. json, xml 받아오기(CInternetSession, HttpSendRequest)

이 글을 보기 전에 이전 글 먼저 봐주시기 바랍니다.


저번 글에 이어서 오늘은 json과 xml을 받아오는 방법을 알아보겠습니다.
총 두 가지 방법이 있는데 두 가지 방법 다 알아보겠습니다.

MFC 프로젝트를 하나 생성해 주시고  아래와 같이 컨트롤을 배치해 놓습니다.

URL 우측 에디트 박스에 아래 그림과 같이 URL을 입력할 예정입니다. 빨간색은 제 인증키입니다.

1. CInternetSession

첫 번째 방법은 CInternetSession을 이용하는 방법입니다. 해당 방법이 더 코드가 짧고 쉽습니다.

CInternetSession을 사용하시려면 아래 헤더파일을 입력해야합니다.

#include <afxinet.h>

CInternetSession 버튼을 더블 클릭하여 아래와 같이 코딩합니다.

void CMFCApplication1Dlg::OnBnClickedButtonCInternetSession()
{
	UpdateData(TRUE);

	// 세션이 연결된 이후, 웹 사이트의 Html 정보가 변경된 사항을 가져올 경우 
	CInternetSession session( NULL, 1, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_DONT_CACHE );

	try
	{
		// 세션 클래스를 이용하여 열기
		CInternetFile *pinetFile = (CInternetFile *)session.OpenURL( m_sUrl );

		if ( NULL != pinetFile )
		{
			char acRead[40960] = { 0, }; // return 값이 길 수 있으므로 충분히 입력
			memset( acRead, 0, sizeof( acRead ) );

			// json 읽는 부분
			UINT uiTotalRead = 0;
			int iIdex = 0;
			do 
			{
				// 데이터를 1024씩 읽어 온다.
				uiTotalRead = pinetFile->Read( &acRead[iIdex], 1024 );
				if ( uiTotalRead <= 0 )
					break;

				iIdex += uiTotalRead;
			} while ( uiTotalRead > 0 );

			// 읽은 json 표시를 위한 부분
			std::string strJson = acRead;
			m_sResult = CA2W( strJson.c_str(), CP_UTF8 );

			pinetFile->Close(); // Html 파일을 닫는다.			
			session.Close(); // 세션 종료

			delete pinetFile; // Html 파일 읽기에 사용한 객체를 파괴			
		}

	}
	catch ( CInternetException *e )
	{
		// 에러
	}

	UpdateData( FALSE );
}

2. HttpSendRequest

두번째 방법은 좀 더 복잡합니다.
우선 먼저 아래 헤더파일과 라이브러리를 추가합니다.

#include <WinInet.h>
#pragma comment(lib, "Wininet.lib")

HttpSendRequest 버튼을 더블클릭하여 아래와 같이 코딩합니다.

void CMFCApplication1Dlg::OnBnClickedButtonHttpSendRequest()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
	UpdateData( TRUE );

	TCHAR szHostName[INTERNET_MAX_HOST_NAME_LENGTH + 1] = { 0, };
	TCHAR szUrlPath[INTERNET_MAX_PATH_LENGTH + 1] = { 0, };
	TCHAR szExtraInfo[INTERNET_MAX_PATH_LENGTH + 1] = { 0, };

	URL_COMPONENTS urlComponents;
	memset( &urlComponents, 0, sizeof( URL_COMPONENTS ) );
	urlComponents.dwStructSize = sizeof( URL_COMPONENTS );

	urlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
	urlComponents.lpszHostName = szHostName;
	urlComponents.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
	urlComponents.lpszUrlPath = szUrlPath;
	urlComponents.dwExtraInfoLength = INTERNET_MAX_PATH_LENGTH;
	urlComponents.lpszExtraInfo = szExtraInfo;

	TCHAR szUrl[40960] = { 0, };
	_tcscpy_s( szUrl, 40960, m_sUrl );
	InternetCrackUrl( szUrl, 0, ICU_DECODE, &urlComponents ); // 입력한 url을 분해

	// internet open
	HINTERNET hInternet = ::InternetOpen( _T( "Seoul Open API Test" ), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
	if ( hInternet != NULL )
	{
		// internet connect
		HINTERNET hConnect = ::InternetConnect( hInternet, urlComponents.lpszHostName, urlComponents.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1 );
		if ( hConnect != NULL )
		{
			DWORD dwFlags = INTERNET_FLAG_RELOAD;

			// http open request
			HINTERNET hRequest = ::HttpOpenRequest( hConnect, NULL, urlComponents.lpszUrlPath, HTTP_VERSION, NULL, NULL, dwFlags, 0 );

			if ( hRequest != NULL )
			{
				// http send request
				BOOL bRequest = FALSE;
				bRequest = ::HttpSendRequest( hRequest, NULL, 0, NULL, 0 );

				if ( bRequest )
				{
					char acRead[40960] = { 0, };
					// return 데이터
					BYTE *pbyBuffer = (BYTE *)acRead;
					DWORD dwLen = 0;
					int nCount = 0;
					while ( true )
					{
						::InternetReadFile( hRequest, pbyBuffer + nCount, 1024, &dwLen );
						if ( dwLen <= 0 )
							break;

						nCount += dwLen;
					}
					pbyBuffer[nCount] = 0;

					std::string strJson = acRead;
					m_sResult = CA2W( strJson.c_str(), CP_UTF8 );
				}

				::InternetCloseHandle( hRequest );
			}

			::InternetCloseHandle( hConnect );
		}

		::InternetCloseHandle( hInternet );
	}

	UpdateData( FALSE );
}

프로그램 실행 후 보시면 아래와 같이 같은 문자열이 출력 됩니다.

xml은 URL에서 json부분을 xml으로 변경하시면 됩니다.

http://openapi.seoul.go.kr:8088/sample/xml/bikeList/1/5/

json과 xml은 서울시에서 제공해줘야 받을 수 있습니다. 자전거 실시간 대여 상황 xml도 지원해준다고 써져있는데 되지 않네요.
웹 관련 공부를 해본적이 없어 개념에 대해 자세히 설명을 드릴 순 없지만 결국은 요청한 URL에 대해 결과를 받아오는 방식입니다.

첫번째, 두번째에 사용된 CInternetFile::Read나 InternetReadFile로 파일을 다운받을 수도 있습니다.

어쨌든 json과 xml을 읽었고, 다음 글에서는 json을 파싱하는 법에 대해 알아보도록 하겠습니다.