티스토리 뷰

IT/Network

[WinSock2] 도메인 이름을 이용하여 IP주소 정보 구하기(getaddrinfo, GetAddrInfo)

주인장 진빼이

과거엔 gethostbyname() 함수를 호출했으나 이젠 depcated 되어 사용 시 다음과 같은 오류가 발생된다.

강제적으로 사용하고 싶다면 오류 내용에 적혀 있듯이 "_WINSOCK_DEPRECATED_NO_WARNINGS" 를 define 하자.

'gethostbyname': Use getaddrinfo() or GetAddrInfoW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings

 

 

MS(Microsoft)에서 사용을 권하고 있는 getaddrinfo(), GetAddrInfo() 함수에 대해 알아볼 것이다.

두 함수는 도메인 주소에 해당하는 IP주소를 얻어올 수 있다.

getaddrinfo() 함수를 호출했다면 결과값을 사용 및 복사 후 freeaddrinfo() 함수를 호출하여 사용했던 리소스를 반납해야 한다.

 

 

prototype

//==== ANSI ====//
#define GetAddrInfoA    getaddrinfo
INT WSAAPI getaddrinfo(
  PCSTR           pNodeName,
  PCSTR           pServiceName,
  const ADDRINFOA *pHints,
  PADDRINFOA      *ppResult
);
ADDRINFOA, *PADDRINFOA;

//==== UNICODE ====//
INT
WSAAPI
GetAddrInfoW(
    _In_opt_        PCWSTR              pNodeName,
    _In_opt_        PCWSTR              pServiceName,
    _In_opt_        const ADDRINFOW *   pHints,
    _Outptr_        PADDRINFOW *        ppResult
    );

 

 

매개변수와 반환 값

멤버 설명
[in]PCSTR pNodeName 도메인 주소
[in]PCSTR pServiceName 서비스 이름 및 포트번호
[in]const ADDRINFO *pHints 힌트를 제공하는 ADDRINFO 구조체의 주소
[out]PADDRINFO ppResult 주소 정보를 받을 구조체 포인터의 주소 (**)
필요한 헤더: WS2tcpip.h

pNodeName에 "localhost"를 전달한다면 루프백 주소가 반환되고 Windows Server 2003 이상에서 "localmachine" 문자열을 전달하는 경우 로컬 컴퓨터에 등록된 모든 주소가 반환된다.

pHints 구조체에서 ai_addrlen, aicanonname, ai_addr, ai_next 멤버들은 반드시 0(NULL) 값이어야 한다.

힌트 구조체에 정보를 미리 등록하여 해당하는 주소 정보를 얻을 수 있다.

 

서비스 이름(pServiceName) 목록은 다음 링크를 참고하자 

 
함수가 성공적으로 실행되어 반환됬다면 0을 반환하고 전달했던 매개변수(ppResult)에 주소 정보가 담긴 구조체를 반환한다. 그외 값은 오류코드(error_code)를 반환한다. gai_strerror() 함수를 호출하면 자세한 오류 내용을 알 수 있다. 함수를 호출할 때 반환받은 오류 코드를 전달해야 한다.
 

전달한 매개변수로 반환된 주소 정보 구조체 addrinfo

> 다음 글 참고

 

예제: brunch.co.kr 도메인에 대한 IP주소 정보 얻어오기

addrHint 정보를 이용해 주소체계, 프로토콜과 스트림 종류에 해당하는 주소 정보를 얻으려고 한다.

예제에서는 burnch.co.kr 사이트를 대상으로 도메인 이름에 대한 IP 주소 정보로 얻으려고 한다.

addrinfo addrHint = { 0, };
addrHint.ai_socktype = SOCK_STREAM;
addrHint.ai_protocol = IPPROTO_TCP;
addrHint.ai_family = AF_INET;

addrinfo *pAddrInfo = nullptr;
char nodeName[32] = "brunch.co.kr";
char serviceName[6] = "http";
getaddrinfo(nodeName, serviceName, &addrHint, &pAddrInfo);
int i = 1;
while (p != nullptr)
{
    cout << "IDX: " << i++;
    cout << pAddrInfo->ai_family << "\n";
    cout << pAddrInfo->ai_protocol << "\n";
    cout << pAddrInfo->ai_socktype << "\n";

    char ip[16];
    inet_ntop(pAddrInfo->ai_family, &pAddrInfo->ai_addr->sa_data[2], ip, pAddrInfo->ai_addrlen);
    cout << ip << "\n";

    p = p->ai_next;
}
freeaddrinfo(pAddrInfo);

 

반환된 주소 정보 구조체(pAddrInfo)에서 inet_ntop() 함수를 호출하여 ip 주소를 구할 수 있다.

아래 결과값에서 2는 AF_INET의 상수 값, 6은 IPPROTO_TCP의 상수 값, 1은 SOCK_STREAM의 상수값이다.

마지막 줄을 보면 정상적으로 도메인에 대한 IP 주소 정보를 얻어올 수 있는 것을 확인할 수 있다.

2
6
1
27.0.237.145

 

 

직접 만든 gethostbyname 확장 함수

gethostbyanem은 매우 편리한 함수이다. deprecated되어 마음이 아프다. 그래서 getaddrinfo() 함수를 이용하여 직접 만들었다.

예외처리는 조금 부족한것 같다.

//gethostbyname_("brunch.co.kr");
string gethostbyname_(const string& domainName)
{
	addrinfo *pAddrInfo = nullptr;
	addrinfo addrHint = { 0, };
	addrHint.ai_family = AF_INET;
	int res = getaddrinfo(domainName.c_str(), "http", &addrHint, &pAddrInfo);
	string ip;
	if (res == 0)
	{
		inet_ntop(AF_INET, &pAddrInfo->ai_addr->sa_data[2], &ip[0], 16);
	}
	else {
		cout << "gethostbyname error:" << gai_strerror(res);
	}
	if (pAddrInfo != nullptr)
	{
		freeaddrinfo(pAddrInfo);
	}
	return ip;
}
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함