개요
getaddrinfo는 domain address를 받아서 네트워크 주소 정보(IP address)를 가져오는 함수이다.
예를들면, http://www.google.co.kr라는 domain address가 있는데, 이 주소는 사람이 알아보기 쉬운 주고이긴 하지만, 컴퓨터는 이 주소를 가지고 해당되는 구글의 서버를 찾아가지 못한다. 그래서 이 domain address와 대응되는 IP주소가 무엇인지를 알아 낸 뒤에 그 IP주소로 연결을 해야한다.
즉, Domain address -> IP address 변환을 하고 싶을 때 사용하는 함수라는 뜻이다.
이걸 전문용어로 DNS (Domain Name System/Service) resolving 이라고 한다.
getaddrinfo 함수는 총 4개의 매개변수를 가진다.
그 중, 1~3번째는 입력 매개변수이고, 4번째 매개변수는 결과를 사용자에게 돌려주는 출력 매개변수이다.
결과는 addrinfo 구조체 (strcut addrinfo) 의 linked list로 돌려준다.
이 결과는 사용을 끝낸 뒤엔 freeaddrinfo 함수로 메모리 해제를 해주어야 한다. 그렇지 않으면 메모리 누수가 발생한다.
관련헤더
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
함수원형
int getaddrinfo(const char *hostname,
const char *service,
const struct addrinfo *hints,
struct addrinfo **result);
void freeaddrinfo(struct addrinfo *res);
getaddrinfo 함수의 매개변수는 총 4개이다.
hostname [in] : 호스트 이름 혹은 주소 문자열(주소 문자열은 => IPv4의 점으로 구분하는 10진 주소 문자열이거나 IPv6의 16진 문자열)
service [in] : 서비스 이름 혹은 10진수로 표현한 포트 번호 문자열
hints [in] : getaddrinfo 함수에게 말그대로 힌트를 준다. 희망하는 유형을 알려주는 힌트를 제공한다. addrinfo 구조체에 hint로 줄 정보를 채운 뒤, 그것의 주소값을 넘기면 된다. 이 힌트는 반환받을 result를 제한하는 기준을 지정하는 것이다. 예를들면, IPv4주소만 받고 싶거나, IPv6주소만 받고 싶을 수도 있고, 둘다 받고 싶을수도 있다. 이럴땐hints의 ai_family의 값을 조작하면 된다. 별도의 hint를 제공하지 않을 경우, NULL을 넣는다.
result [out] : DNS서버로부터 받은 네트워크 주소 정보(IP 주소)를 돌려주는 output 매개변수이다. addrinfo 구조체를 사용하며, 링크드 리스트이다. 이 addrinfo 구조체에 대해서는 아래 그림을 참고하면 이해하기 쉽다. 이 result의 내용중 필요한것들은 적절히 copy하여 사용자의 변수로 옮겨두어야 하며, result는 사용이 끝나는 즉시 freeaddrinfo 함수로 메모리 해제를 해주어야 한다.
getaddrinfo가 반환한 주소정보(addrinfo)의 예
반환 값
이 함수는 성공하면 0을 반환하다.
실패하면 0이 아닌 값을 반환하는데, 아래 에러 값들중 하나를 반환하게 된다.
EAI_ADDRFAMILY
지정된 네트워크 호스트에 요청했던 address family 주소가 없는 경우이다. 예를들어 IPv4주소만 갖는 네트워크 호스트에게 'IPv6주소를 내놔라' 하고 요청한다면, 이런 에러가 반환된다.
EAI_AGAIN
nameserver가 일시적인 오류 표시를 반환했다. 일정 시간 이후에 다시 시도하라는 의미이다.
EAI_BADFLAGS
hints.ai_flags에 잘못된 플래그가 포함되어 있다. 또는 hints.ai_flags에는 AI_CANONNAME이 포함되었고 이름이 NULL인 경우이다.
EAI_FAIL
nameserver가 지속되는 오류 표시를 반환했다. EAI_AGAIN과는 달리 다시 시도해도 실패할 것이라는 의미다.
EAI_FAMILY
요청한 address family는 지원되지 않는다.
EAI_MEMORY
getaddrinfo를 수행하기에 메모리가 부족한 경우다. 거의 막장인 상황이다. kernel의 OOM killer가 제대로 작동하길 기대하면서 기다렸다가 일정 시간 지난 후 재시도 해보고 그래도 같은 에러를 받는다면 속편하게 재부팅 하라.
EAI_NODATA
지정한 네트워크 호스트가 있긴 한데... 네트워크 주소가 정의되어 있지 않은 경우다.
EAI_NONAME
노드 또는 서비스를 알 수 없다.
또는 노드와 서비스 모두가 NULL이다.
또는 AI_NUMERICSERV가 hints.ai_flags에 지정되었는데, 정작 service는 포트 번호를 나타내는 숫자형태의 문자열이 아니었다.
어떤 경우이건, 입력 매개변수를 잘못 넣었다는 의미다. 자신이 매개변수를 잘 넣었는지? 스스로의 코드를 다시 점검 해볼 것.
EAI_SERVICE
요청한 서비스를 요청한 소켓 유형에 사용할 수 없다. 다른 소켓 유형을 통해 사용할 수 있다. 예를 들어 서비스가 "쉘"(스트림 소켓에서만 사용할 수있는 서비스)이고 hints.ai_protocol이 IPPROTO_UDP이거나 hints.ai_socktype이 SOCK_DGRAM 인 경우 이 오류가 발생할 수 있다.
또는 서비스가 NULL이 아니고 hints.ai_socktype이 SOCK_RAW (서비스 개념을 지원하지 않는 소켓 유형) 인 경우 오류가 발생할 수 있습니다.
EAI_SOCKTYPE
요청한 소켓 유형이 지원되지 않는다.
예를 들어, hints.ai_socktype 및 hints.ai_protocol이 일치하지 않는 경우다. ai_socktype에는 SOCK_DGRAM 를 넣고, ai_protocol에는 IPPROTO_TCP를 넣은 hint를 입력 매개변수로 넘기면 발생할 수 있는 에러이다.
EAI_SYSTEM
위 모든 경우를 제외한 뭔가 다른 시스템 오류다, 골치아픈 경우다. 자세한 내용은 errno를 확인해야 하는 경우다.
반환값의 해석
const char *gai_strerror(int errcode);
gai_strerror( ) 함수를 이용한다.
이 함수는 getaddrinfo( )가 return한 오류 코드를 사람이 읽을 수 있는 문자열로 변환해준다.
디버깅, 로그 출력 시 도움이 되니 참고할 것.
예제
아래는 www.google.com 80포트의 Network Address 정보를 얻는 예제이다.
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int main(int argc,char *argv[])
{
int status;
struct addrinfo hints;
struct addrinfo *servinfo; // 결과를 저장할 변수
memset(&hints, 0, sizeof(hints)); // hints 구조체의 모든 값을 0으로 초기화
hints.ai_family = AF_UNSPEC; // IPv4와 IPv6 상관하지 않고 결과를 모두 받겠다
hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
status = getaddrinfo("www.google.com", "80", &hints, &servinfo);
}
공식 근거문서
POSIX.1-2001. getaddrinfo( ) 함수는 RFC 2553에 문서화 되어 있다.
중요 알림사항
getaddrinfo( ) 는 IPv6 scope-ID를 지정하기 위한 address%scope-id 표기법을 지원한다.
AI_ADDRCONFIG, AI_ALL 및 AI_V4MAPPED는 glibc 2.3.3부터 사용할 수 있다.
AI_NUMERICSERV는 glibc 2.3.4부터 사용 가능하다.
POSIX.1-2001에 따르면, hint를 NULL로 지정하면 ai_flags가 0으로 간주된다. 그러나 GNU C 라이브러리는 이 값이 향상을 위한 것으로 간주하기 때문에, 이렇게 hint가 NULL인 경우에는 ai_flags를 0 대신 (AI_V4MAPPED | AI_ADDRCONFIG) 값을 사용합니다.
같이보기
inet_pton( ) 함수
'개발자의 기록 노트 > C' 카테고리의 다른 글
[네트워크/C reference] inet_ntop 함수 (0) | 2017.11.02 |
---|---|
[C][CURL] CURLOPT_FOLLOWLOCATION 의 버전별 동작 차이 (0) | 2017.08.31 |
[네트워크/C] addrinfo 구조체 (0) | 2017.06.16 |
[네트워크/C] sockaddr, sockaddr_in, sockaddr_un 구조체 - 소켓 주소 정보를 나타낸다 (1) | 2017.06.14 |
[네트워크/C] ifreq 구조체 (struct ifreq) (0) | 2017.06.14 |
[C] 저수준 파일 입출력 (0) | 2011.10.03 |