소켓 프로그래밍을 짜는데 자꾸 도메인을 ip로 바꿀 때 어떤 함수를 썼고 어떤 방식으로 코드를 짰는지 헷갈려서 정리를 하려합니다.
도메인을 IP 구조체로 바꿀 때 옛날 책을 보면 gethostbyname이라는 함수를 사용하라고 합니다.
하지만 이 함수는 유니코드를 지원하지 않고 너무 옛날 방식이기 때문에 MSDN에서도 해당 함수를 보면 이렇게 써있습니다.
참고 : gethostbyname 함수는 getaddrinfo 함수를 도입하여 더 이상 사용되지 않습니다. Windows Sockets 2 애플리케이션을 만드는 개발자는 gethostbyname 대신 getaddrinfo 함수를 사용해야 합니다.
그러므로 getaddrinfo 함수를 쓰면 되는 것이죠.
우선 GetAddrInfo 함수를 쓰려면 일단 ws2tcpip.h 헤더를 인클루드 해줘야 합니다.
이 함수는 유니코드도 지원하고 ANSI 문자열도 지원합니다.
GetAddrInfo 함수를 쓰면 알아서 환경에 따라 변환해 줍니다.
우선 유니코드 기반으로 쓰는 것을 설명하겠습니다.
함수 형태는 다음과 같습니다.
INT WSAAPI GetAddrInfoW(
[in, optional] PCWSTR pNodeName,
[in, optional] PCWSTR pServiceName,
[in, optional] const ADDRINFOW *pHints,
[out] PADDRINFOW *ppResult
);
1) pNodeName : 여기에 도메인 이름을 넣습니다.
2) pServiceName : 문자열로 표시되는 서비스 이름 또는 포트 번호를 포함하는 NULL로 종료된 유니코드 문자열에 대한 포인터입니다.
3) pHints : 호출자가 지원하는 소켓 유형에 대한 힌트를 제공하는 addrinfoW 구조체에 대한 포인터입니다.
4) ppResult : 호스트에 대한 응답 정보를 포함하는 하나 이상의 addrinfoW 구조체의 연결된 목록에 대한 포인터입니다.
5) 반환값 : 성공 시 0을 반환한다.
매개 변수만 보면 뭔가 복잡해 보이는데요. 2번 매개변수와, 3번 매개변수는 저도 솔직히 잘 이해가 되지 않습니다.
그래도 제 목적은 도메인 이름으로 IP주소를 얻는 것이므로 그 방법만 알아보려합니다.
#include <ws2tcpip.h>
int main()
{
//GetAddrInfo 함수를 쓰기 위한 ADDRINFOW구조체 이 함수를 쓰는 이유는 매개변수로 버퍼를 받고, 유니코드를 지원하기 때문이다.
//이 구조체는 링크드 리스트 형태로 한 도메인에 설정된 여러 아이피 정보를 물고있다.
ADDRINFOW* addrInfo;
//소켓 주소 구조체 선언
SOCKADDR_IN* sockAddr;
GetAddrInfo(L"www.naver.com", L"0", NULL, &addrInfo)
//소켓 주소 구조체로 형변환 해서 원하는 도메인에 해당하는 ip를 가지는 소켓 주소 구조체를 얻을 수 있다.
sockAddr = (SOCKADDR_IN*)(addrInfo->ai_addr);
//GetAddrInfo 함수는 FreeAddrInfo 함수를 호출해서 리소스를 반환해줘야 한다.
FreeAddrInfo(addrInfo);
}
이런 식으로 쓸 수 있습니다.
참고로 하나의 도메인에는 여러 IP 주소가 할당될 수 있습니다.
그래서 addrInfo 구조체는 리스트의 형태로 여러 addrInfo 구조체가 이어져 있습니다. addrInfo의 멤버에는 ai_next라는 멤버가 있는데 이 멤버로 다음 addrInfo 구조체로 가서 여러 IP에 접근할 수 있습니다.
그리고 잊어서는 안되는 FreeAddrInfo 함수!
반드시 호출해서 메모리 낭비를 막아야 합니다!
이번에는 IP를 문자열로 바꾸는 방법을 알아봅시다.
흔히 서버 주소를 세팅할 때 IN_ADDR으로 변환해야 하는 경우가 있습니다.
코드를 보시죠
SOCKADDR_IN serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
InetPton(AF_INET, L"192. 168.0.3", &serverAddr.sin_addr);
serverAddr.sin_port = htons(SERVERPORT);
이렇게 InetPton 함수로 IP 문자열을 IN_ADDR 형태로 변환해줄 수 있습니다. 이 때 네트워크 바이트 배열로도 바뀌므로 htonl을 할 필요도 없습니다.
InetNtop() 함수로 쉽게 할 수 있습니다.
WCHAR serverIPStr[16] = { 0 };
InetNtop(AF_INET, &serverAddr.sin_addr, serverIPStr, 16);
버퍼 하나 준비해주시고 인자로 넘기면 그 버퍼에 IP 문자열이 들어가게 됩니다.