컴퓨터 사이언스/Network

호스트와 서비스 변환

kimjingyu 2023. 11. 19. 13:49
728x90

getaddrinfo()

모든 프로토콜에 대해 호스트 이름, 호스트 주소, 포트 번호, 서비스 이름을 소켓 주소 구조체로 변환해준다. 즉, 네트워크 호스트 정보를 받아서 IP address를 가져오거나, 그 반대를 수행하는 함수이다. 특징으로는 멀티 쓰레딩시에 문제가 없고, IPv4나 IPv6 등 특정 IP protocol에 의존할 필요가 없다는 점이 있다.

int getaddrinfo(const char *host,            /* Hostname or address */
                const char *service,         /* Port or service name */
                const struct addrinfo *hints,/* Input parameters */
                struct addrinfo **result);   /* Output linked list */

/* 메모리 누수를 피하기 위해 addrinfo 구조체 리스트를 반환한다. */
void freeaddrinfo(struct addrinfo *result);  /* Free linked list */

/* 에러 시에 에러 코드를 메세지로 바꿔준다. */
const char *gai_strerror(int errcode);

 

사용 예시

#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); 
}

 

 

addrinfo 구조체 리스트

IP address와 호스트 이름을 표현한데 사용된다. 클라이언트는 이 리스트를 방문하면서 각각의 소켓 주소를 socket()과 connect()가 성공할 때까지 계속 테스트한다. 서버는 socket()과 bind()가 성공할 때까지 계속 테스트한다. 테스트에 성공하면 result에 그 소켓 주소 구조체를 가리키는 포인터를 반환한다.

struct addrinfo {
    int              ai_flags;     /* Hints argument flags */
    int              ai_family;    /* First arg to socket function */
    int              ai_socktype;  /* Second arg to socket function */
    int              ai_protocol;  /* Third arg to socket function  */
    char            *ai_canonname; /* Canonical host name */
    size_t           ai_addrlen;   /* Size of ai_addr struct */
    struct sockaddr *ai_addr;      /* Ptr to socket address structure */
    struct addrinfo *ai_next;      /* Ptr to next item in linked list */
};

 

getnameinfo

getaddrinfo의 반대 기능을 하는 함수로, 네트워크 주소 정보(소켓 주소 구조체, IP address)를 받아 그에 대응하는 호스트와 서비스 이름(도메인 주소)를 반환해준다. 즉, 32비트 IP address를 입력하면 dotted-decimal 주소나 도메인 이름을 반환한다.

int getnameinfo(const SA *sa, socklen_t salen, /* In: socket addr */
                char *host, size_t hostlen,    /* Out: host */
                char *serv, size_t servlen,    /* Out: service */
                int flags);                    /* optional flags */

 

HOSTINFO 프로그램

도메인 이름을 main()의 인자로 넣었을 때, IP address로 반환한다.

#include "csapp.h"

int main(int argc, char **argv)
{
    struct addrinfo *p, *listp, hints;
    char buf[MAXLINE];
    int rc, flags;
    
    // getaddrinfo()를 사용해 addrinfo 리스트를 받는다.
    memset(&hints, 0, sizeof(struct addrinfo));  // hint 구조체 초기화
    hints.ai_family = AF_INET;       /* IPv4의 주소만 반환해주세요 */
    hints.ai_socktype = SOCK_STREAM; /* TCP 연결 */


    if ((rc = getaddrinfo(argv[1], NULL, &hints, &listp)) != 0) {
        fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(rc));
        exit(1);
    }
    
    // getnameinfo()를 이용해 addrinfo 리스트에 있는 IP address들을 출력한다.
    flags = NI_NUMERICHOST; /* 도메인 이름을 리턴하지 않고 10진수 주소 스트링을 대신 리턴한다. */
    for (p = listp; p; p = p->ai_next) {
        getnameinfo(p->ai_addr, p->ai_addrlen,  // addrinfo 안의 IP주소(소켓 주소 구조체)를 찾아
                    buf, MAXLINE,   // 호스트 이름. flag를 썼으니 10진수 주소로.
                    NULL, 0,        // service는 안받아오는듯
                    flags);
        printf("%s\n", buf);  // input IP주소를 출력한다.

    }

    /* addrinfo 구조체를 free한다. */
    freeaddrinfo(listp);

    exit(0);
}
728x90