getaddrinfo(3)
- https://man7.org/linux/man-pages/man3/getaddrinfo.3.html
- 0017 C ๐
- 11. Network Programming {CSAPP}#11.4.7. Host and Service Conversion ์์ ๊ฑด๋์ด
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo(const char *restrict node,
const char *restrict service,
const struct addrinfo *restrict hints,
struct addrinfo **restrict res);
void freeaddrinfo(struct addrinfo *res);
const char *gai_strerror(int errcode);
struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *ai_next;
};
hostname, host address, service name, port number๋ฅผ ํ๋ฐ๋ชจ์ ํ๋์ struct addrinfo
๊ตฌ์กฐ์ฒด์ ๋ด์์ฃผ๋ ์น์ ํ ํจ์์ด๋ค. ์ด์ค ํฌ์ธํฐ์ธ ์ด์ ๋ CSAPP Figure 11.15์์ ๋ณผ ์ ์๋ค์ํผ ์ฐ๊ฒฐ๋ฆฌ์คํธ์ ์ฒซ ์ฃผ์๋ฅผ ๊ฐ๋ฆฌํค๊ณ ์๊ธฐ ๋๋ฌธ์ด๋ค. ์ฐ๊ฒฐ๋ฆฌ์คํธ head๋ฅผ ์ด์ค ํฌ์ธํฐ๋ก ๋ง๋ ๋๋ถ์ ํฌ์ธํฐ์ ๊ฐ์ getaddrinfo
๊ฐ ์ค์ค๋ก ํ ๋นํด์ ๊ทธ ์์น๋ฅผ ๋จน์ผ ์ ์๊ฒ ๋์๋ค.
getaddrinfo
๋ ํ ๋ฉ๋ชจ๋ฆฌ ์์ญ ์์ ํ ๋น๋ฐ์ ์ฐ๊ฒฐ๋ฆฌ์คํธ๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ freeaddrinfo
ํจ์๋ฅผ ํธ์ถํ์ฌ ์ ๊ฑฐํด ์ฃผ์ด์ผ ํ๋ค.
gpt question: getaddrinfo(NULL, ...)
ํ๋ ์ด์
Question
๋ค์ ํจ์๋ getaddrinfo๋ฅผ ์ฌ์ฉํ์ฌ struct addrinfo ๋ฆฌ์คํธ๋ฅผ ์ป์ด๋ด ์ํ๋ฅผ ๋๋ฉด์ socket, bind ํจ์๋ฅผ ํธ์ถํด. ์ฌ๊ธฐ์ ๊ถ๊ธํ ์ ์ ์ getaddrinfo ์ฒซ๋ฒ์งธ ์ธ์๋ฅผ NULL๋ก ์ฃผ๋๊ฑฐ์ผ? ip์ฃผ์๊ฐ ๋ค์ด๊ฐ๋ ์๋ฆฌ์ธ ๊ฑธ๋ก ์๋๋ฐ NULL์ด ๋ค์ด๊ฐ๋ฉด ๋ฌด์์ผ๋ก ๋์ฒด๋๋์ง ๊ถ๊ธํด.
/*
* open_listenfd - Open and return a listening socket on port. This
* function is reentrant and protocol-independent.
*
* On error, returns:
* -2 for getaddrinfo error
* -1 with errno set for other errors.
*/
/* $begin open_listenfd */
int open_listenfd(char *port)
{
struct addrinfo hints, *listp, *p;
int listenfd, rc, optval=1;
/* Get a list of potential server addresses */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM; /* Accept connections */
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* ... on any IP address */
hints.ai_flags |= AI_NUMERICSERV; /* ... using port number */
if ((rc = getaddrinfo(NULL, port, &hints, &listp)) != 0) {
fprintf(stderr, "getaddrinfo failed (port %s): %s\n", port, gai_strerror(rc));
return -2;
}
/* Walk the list for one that we can bind to */
for (p = listp; p; p = p->ai_next) {
/* Create a socket descriptor */
if ((listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)
continue; /* Socket failed, try the next */
/* Eliminates "Address already in use" error from bind */
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, //line:netp:csapp:setsockopt
(const void *)&optval , sizeof(int));
/* Bind the descriptor to the address */
if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0)
break; /* Success */
if (close(listenfd) < 0) { /* Bind failed, try the next */
fprintf(stderr, "open_listenfd close failed: %s\n", strerror(errno));
return -1;
}
}
/* Clean up */
freeaddrinfo(listp);
if (!p) /* No address worked */
return -1;
/* Make it a listening socket ready to accept connection requests */
if (listen(listenfd, LISTENQ) < 0) {
close(listenfd);
return -1;
}
return listenfd;
}
answer
getaddrinfo
ํจ์์์ ์ฒซ ๋ฒ์งธ ์ธ์๋ฅผ NULL
๋ก ์ ๋ฌํ๋ ์ด์ ๋ ์๋ฒ ์์ผ์ ์์ฑํ๊ณ , ํด๋น ์์ผ์ ๋ชจ๋ ์ฌ์ฉ ๊ฐ๋ฅํ ๋คํธ์ํฌ ์ธํฐํ์ด์ค(๋ก์ปฌ ์ฃผ์)์ ๋ฐ์ธ๋ฉํ๊ธฐ๋ฅผ ์ํ๊ธฐ ๋๋ฌธ์
๋๋ค.
getaddrinfo
ํจ์์ ์ฒซ ๋ฒ์งธ ์ธ์๋ ํธ์คํธ ์ด๋ฆ์ด๋ IP ์ฃผ์๋ฅผ ๋ํ๋
๋๋ค. ๋ง์ฝ ์ด ์ธ์์ NULL
์ ์ ๋ฌํ๋ฉด, getaddrinfo
๋ ํ์ฌ ํธ์คํธ(๋ก์ปฌ ์์คํ
)์ ๋ํ ๋คํธ์ํฌ ์ธํฐํ์ด์ค ์ฃผ์๋ฅผ ๊ฐ์ ธ์ค๊ฒ ๋ฉ๋๋ค. ์ด๋ ์๋ฒ๊ฐ ํ์ฌ ํธ์คํธ์ ๋ชจ๋ ๋คํธ์ํฌ ์ธํฐํ์ด์ค(์: ๋ชจ๋ IP ์ฃผ์)์์ ๋ค์ด์ค๋ ์ฐ๊ฒฐ์ ์๋ฝํ๊ณ ์ ํ ๋ ์ ์ฉํฉ๋๋ค. ์ฆ, ์๋ฒ๋ ๋ชจ๋ ๋คํธ์ํฌ ์ธํฐํ์ด์ค์ ๋ํ ์ฐ๊ฒฐ์ ์์ ํ๋ ค๊ณ ํ ๋ NULL
์ ์ฌ์ฉํ์ฌ getaddrinfo
๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค.
๋ฐ๋ผ์ getaddrinfo(NULL, port, &hints, &listp)
๋ ํ์ฌ ํธ์คํธ์ ๋ชจ๋ ๋คํธ์ํฌ ์ธํฐํ์ด์ค์์ port
๋ฒํธ๋ก ๋ค์ด์ค๋ ์ฐ๊ฒฐ์ ์๋ฝํ๊ธฐ ์ํ ์ฃผ์ ์ ๋ณด๋ฅผ ์ป๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ด๋ ๊ฒ ์ป์ ์ฃผ์ ์ ๋ณด๋ฅผ ์ด์ฉํ์ฌ ์๋ฒ ์์ผ์ ์์ฑํ๊ณ ํด๋น ์ฃผ์๋ก ๋ฐ์ธ๋ฉํฉ๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ์๋ฒ๋ ๋ชจ๋ ๋คํธ์ํฌ ์ธํฐํ์ด์ค์์ ๋ค์ด์ค๋ ์ฐ๊ฒฐ์ ์์ ํ ์ ์๊ฒ ๋ฉ๋๋ค.
์ ๋ฆฌ
bind๋ฅผ ํ ๋ ๋ฃ๋ struct addrinfo
๊ตฌ์กฐ์ฒด ์์ ๋ค์ด๊ฐ๋ ์ฃผ์์ ํฌํธ์ ๋ํ์ฌ ์ฃผ์๋ฅผ NULL๋ก ์ฃผ๋ฉด ์์์ "ํด๋น ํฌํธ๋ก ๋ค์ด์ค๋ ๋ชจ๋ ํธ์คํธ๋ก๋ถํฐ์ ์ ์์ ํ์ฉํฉ๋๋ค"๋ผ๊ณ ๋ปํ๋ ๊ฒ ๊ฐ๋ค.
gpt question getaddrinfo
hint ๋ฃ๋๋ฒ
question
์๋ฒ์๊ฒ HTTP GET ์์ฒญ์ ์ ์กํ๋ ค๊ณ ํ๋๋ฐ getaddrinfo ํจ์ ์ธ์๋ฅผ ์ด๋ป๊ฒ ๋ฃ์ด์ผ ์ฌ๋ฐ๋ฅธ struct addrinfo ๋ฆฌ์คํธ๋ฅผ ์ป์ ์ ์์๊น?
answer
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
int main() {
struct addrinfo hints, *res;
int status;
// ์๋ฒ ํธ์คํธ ์ด๋ฆ ๋๋ IP ์ฃผ์, ํฌํธ ๋ฒํธ, ํํธ ์ด๊ธฐํ
const char *hostname = "www.example.com"; // ๋์ ์๋ฒ ์ฃผ์
const char *port = "80"; // HTTP ํฌํธ ๋ฒํธ
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // IPv4 ๋๋ IPv6
hints.ai_socktype = SOCK_STREAM; // TCP ์์ผ
// getaddrinfo ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์๋ฒ ์ฃผ์ ์ ๋ณด ์ป๊ธฐ
if ((status = getaddrinfo(hostname, port, &hints, &res)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
return 1;
}
// addrinfo ๋ฆฌ์คํธ(res)๋ฅผ ์ฌ์ฉํ์ฌ ์๋ฒ์ HTTP GET ์์ฒญ์ ์ ์กํ ์ ์์
// addrinfo ๋ฆฌ์คํธ๋ฅผ ์ฌ์ฉํ ํ ๋ฉ๋ชจ๋ฆฌ ํด์
freeaddrinfo(res);
return 0;
}
์ ์์ ์์ ์ฃผ์ํ ๋ถ๋ถ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
getaddrinfo
ํจ์๋ฅผ ํธ์ถํ ๋hostname
๋ณ์์ ๋์ ์๋ฒ์ ํธ์คํธ ์ด๋ฆ ๋๋ IP ์ฃผ์๋ฅผ ์ง์ ํ๊ณ ,port
๋ณ์์๋ HTTP ํฌํธ ๋ฒํธ(์ผ๋ฐ์ ์ผ๋ก 80)๋ฅผ ์ง์ ํฉ๋๋ค.hints
๊ตฌ์กฐ์ฒด๋ฅผ ์ด๊ธฐํํ๊ณ , ํ์ํ ๋คํธ์ํฌ ์์ฑ์ ์ค์ ํฉ๋๋ค. ์์ ์์ ์์๋ IPv4 ๋๋ IPv6 ์ฃผ์๋ฅผ ์ฌ์ฉํ๊ณ , TCP ์์ผ์ ์ง์ ํ์ต๋๋ค.getaddrinfo
ํจ์๋ฅผ ํธ์ถํ์ฌres
ํฌ์ธํฐ๋ฅผ ํตํด ์ฃผ์ ์ ๋ณด๋ฅผ ์ป์ต๋๋ค. ์ด๋ ๊ฒ ์ป์struct addrinfo
๋ฆฌ์คํธ(res
)์๋ ์๋ฒ์ ์ฃผ์ ์ ๋ณด๊ฐ ๋ค์ด ์์ต๋๋ค.addrinfo
๋ฆฌ์คํธ๋ฅผ ์ฌ์ฉํ์ฌ HTTP GET ์์ฒญ์ ์๋ฒ์ ์ ์กํ ์ ์์ต๋๋ค. ์ด ๋ถ๋ถ์ HTTP ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์์ผ ํ๋ก๊ทธ๋๋ฐ์ ํตํด ์ํํ ์ ์์ต๋๋ค.- ์์
์ด ๋๋ ํ, ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด
freeaddrinfo
ํจ์๋ฅผ ์ฌ์ฉํ์ฌres
์ ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํด์ ํฉ๋๋ค.
์ด๋ ๊ฒ ์ค์ ๋ getaddrinfo
ํจ์ ํธ์ถ์ ํตํด ์ฌ๋ฐ๋ฅธ ์๋ฒ ์ฃผ์ ์ ๋ณด๋ฅผ ์ป๊ณ , ์ด๋ฅผ ์ฌ์ฉํ์ฌ HTTP GET ์์ฒญ์ ์ ์กํ ์ ์๊ฒ ๋ฉ๋๋ค.