μ‚¬μš©ν•  ν•¨μˆ˜μ— λŒ€ν•œ 질문 ( feat. chatGPT )

πŸ…€ gai_strerror κ°€ 뭐지?

πŸ„°

gai_strerror() ν•¨μˆ˜λŠ” λ„€νŠΈμ›Œν¬ ν•¨μˆ˜ 쀑에 getaddrinfo()λ‚˜ getnameinfo()와 ν•¨κ»˜ μ‚¬μš©λ˜λ©°, 이 ν•¨μˆ˜λ“€μ΄ λ°˜ν™˜ν•˜λŠ” 였λ₯˜ μ½”λ“œλ₯Ό λ¬Έμžμ—΄λ‘œ λ³€ν™˜ν•˜λŠ” 역할을 ν•©λ‹ˆλ‹€.
즉, gai_strerror() ν•¨μˆ˜λŠ” 인자둜 받은 error μ½”λ“œμ— ν•΄λ‹Ήν•˜λŠ” 였λ₯˜ λ©”μ‹œμ§€λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. 이 ν•¨μˆ˜λŠ” 헀더 νŒŒμΌμ— μ„ μ–Έλ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.
예λ₯Ό λ“€μ–΄, getaddrinfo() ν•¨μˆ˜κ°€ μ‹€νŒ¨ν•˜λ©΄ ν•΄λ‹Ή ν•¨μˆ˜λŠ” -1을 λ°˜ν™˜ν•˜κ³ , 였λ₯˜ μ •λ³΄λŠ” gai_strerror() ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜μ—¬ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.



πŸ…€ htons κ°€ 뭐야?

πŸ„°

htons() ν•¨μˆ˜λŠ” "Host to Network Short"의 μ•½μ–΄λ‘œ, 16λΉ„νŠΈ short ν˜•μ‹μ˜ 데이터λ₯Ό 호슀트 λ°”μ΄νŠΈ μ˜€λ”λ‘œ ν‘œν˜„λœ λ°μ΄ν„°μ—μ„œ λ„€νŠΈμ›Œν¬ λ°”μ΄νŠΈ μ˜€λ”λ‘œ λ³€ν™˜ν•˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€.

λ„€νŠΈμ›Œν¬ λ°”μ΄νŠΈ μ˜€λ”λŠ” λΉ… μ—”λ””μ•ˆμœΌλ‘œ μ •μ˜λ˜μ–΄ 있기 λ•Œλ¬Έμ—, htons() ν•¨μˆ˜λŠ” ν˜ΈμŠ€νŠΈμ—μ„œ μ‚¬μš©ν•˜λŠ” 리틀 μ—”λ””μ•ˆ λ°”μ΄νŠΈ μ˜€λ”λ₯Ό λ„€νŠΈμ›Œν¬μ—μ„œ μ‚¬μš©ν•˜λŠ” λΉ… μ—”λ””μ•ˆ λ°”μ΄νŠΈ μ˜€λ”λ‘œ λ³€ν™˜ν•©λ‹ˆλ‹€. 이 ν•¨μˆ˜λŠ” 헀더 νŒŒμΌμ— μ„ μ–Έλ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄, short ν˜•μ‹μ˜ λ³€μˆ˜μΈ portκ°€ 리틀 μ—”λ””μ•ˆ λ°”μ΄νŠΈ μ˜€λ”λ‘œ ν‘œν˜„λ˜μ–΄ μžˆλ‹€λ©΄, htons() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ λ„€νŠΈμ›Œν¬ λ°”μ΄νŠΈ μ˜€λ”λ‘œ λ³€ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

#include <arpa/inet.h>

short port = 8080;
unsigned short net_port = htons(port);

μœ„ μ½”λ“œμ—μ„œ net_portλŠ” 16λΉ„νŠΈ short ν˜•μ‹μ˜ port λ³€μˆ˜λ₯Ό λ„€νŠΈμ›Œν¬ λ°”μ΄νŠΈ μ˜€λ”λ‘œ λ³€ν™˜ν•œ κ²°κ³Όλ₯Ό μ €μž₯ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. μ΄λ ‡κ²Œ λ³€ν™˜λœ λ°μ΄ν„°λŠ” λ„€νŠΈμ›Œν¬ μƒμ—μ„œ μ „μ†‘λ˜λŠ” 데이터 ν˜•μ‹κ³Ό ν˜Έν™˜λ˜κΈ° λ•Œλ¬Έμ—, λ„€νŠΈμ›Œν¬ ν”„λ‘œκ·Έλž˜λ°μ—μ„œ 맀우 μ€‘μš”ν•œ 역할을 ν•©λ‹ˆλ‹€.

λ„€νŠΈμ›Œν¬ ν”„λ‘œκ·Έλž˜λ°μ—μ„œ htons() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” κ°„λ‹¨ν•œ 예제λ₯Ό λ³΄μ—¬λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€. 이 μ˜ˆμ œλŠ” ν΄λΌμ΄μ–ΈνŠΈ-μ„œλ²„ λͺ¨λΈμ„ μ΄μš©ν•˜μ—¬ ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„œλ²„λ‘œ λ©”μ‹œμ§€λ₯Ό μ „μ†‘ν•˜λŠ” μ˜ˆμ œμž…λ‹ˆλ‹€.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>

#define SERVER_ADDR "127.0.0.1"
#define SERVER_PORT 8080

int main(int argc, char *argv[]) {
    int sock;
    struct sockaddr_in server_addr;
    char message[256];

    // μ†ŒμΌ“ 생성
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    // μ„œλ²„ μ£Όμ†Œ μ„€μ •
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(SERVER_ADDR);
    server_addr.sin_port = htons(SERVER_PORT);

    // μ„œλ²„μ— μ—°κ²°
    if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("connect");
        exit(EXIT_FAILURE);
    }

    // λ©”μ‹œμ§€ 전솑
    printf("Enter a message: ");
    fgets(message, sizeof(message), stdin);
    write(sock, message, strlen(message));

    // μ†ŒμΌ“ μ’…λ£Œ
    close(sock);
    return 0;
}

μœ„ μ½”λ“œμ—μ„œ htons() ν•¨μˆ˜λŠ” server_addr ꡬ쑰체의 sin_port 멀버에 μ‚¬μš©λ˜μ—ˆμŠ΅λ‹ˆλ‹€. ν΄λΌμ΄μ–ΈνŠΈλŠ” SERVER_PORT μƒμˆ˜ 값을 리틀 μ—”λ””μ•ˆμœΌλ‘œ ν‘œν˜„ν•˜κ³  μžˆμ§€λ§Œ, htons() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ 이λ₯Ό λΉ… μ—”λ””μ•ˆμœΌλ‘œ λ³€ν™˜ν•˜μ—¬ server_addr ꡬ쑰체의 sin_port 멀버에 ν• λ‹Ήν•˜μ˜€μŠ΅λ‹ˆλ‹€. μ΄λ ‡κ²Œ λΉ… μ—”λ””μ•ˆμœΌλ‘œ ν‘œν˜„λœ sin_port 값은 connect() ν•¨μˆ˜μ—μ„œ μ„œλ²„μ™€μ˜ μ—°κ²° μ‹œ μ‚¬μš©λ©λ‹ˆλ‹€.



πŸ…€ select, poll, epoll, kqueue 의 νŠΉμ§•κ³Ό 차이점이 뭐여?

πŸ„°

select, poll, epoll, kqueue은 λͺ¨λ‘ I/O λ©€ν‹°ν”Œλ ‰μ‹± 기법을 κ΅¬ν˜„ν•˜λŠ” μ‹œμŠ€ν…œ μ½œμž…λ‹ˆλ‹€. μ΄λŸ¬ν•œ μ‹œμŠ€ν…œ μ½œμ€ ν•˜λ‚˜μ˜ ν”„λ‘œμ„ΈμŠ€κ°€ μ—¬λŸ¬ 개의 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό λͺ¨λ‹ˆν„°λ§ν•˜κ³ , μ—¬λŸ¬ 개의 파일 λ””μŠ€ν¬λ¦½ν„° μ€‘μ—μ„œ I/O μ΄λ²€νŠΈκ°€ λ°œμƒν•œ 것을 κ°μ§€ν•˜μ—¬ 이λ₯Ό μ²˜λ¦¬ν•  수 μžˆλ„λ‘ λ„μ™€μ€λ‹ˆλ‹€.

ν•˜μ§€λ§Œ select, poll, epoll, kqueue 각각의 νŠΉμ§•κ³Ό 차이점은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

β†˜οΈŽ select
selectλŠ” κ°€μž₯ 였래된 I/O λ©€ν‹°ν”Œλ ‰μ‹± κΈ°λ²•μœΌλ‘œ, 파일 λ””μŠ€ν¬λ¦½ν„°μ˜ μƒνƒœ λ³€ν™”λ₯Ό κ°μ‹œν•˜κΈ° μœ„ν•΄ fd_setμ΄λΌλŠ” λΉ„νŠΈλ§΅ 자료ꡬ쑰λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. selectλŠ” μƒλŒ€μ μœΌλ‘œ κ°„λ‹¨ν•˜κ³ , λŒ€λΆ€λΆ„μ˜ 운영 μ²΄μ œμ—μ„œ μ§€μ›λ©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λΉ„νŠΈλ§΅μ˜ 크기가 μ œν•œλ˜μ–΄ 있기 λ•Œλ¬Έμ—, λͺ¨λ‹ˆν„°λ§ν•  수 μžˆλŠ” 파일 λ””μŠ€ν¬λ¦½ν„°μ˜ μˆ˜μ—λ„ μ œν•œμ΄ μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ, selectλŠ” λͺ¨λ“  파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό 순차적으둜 νƒμƒ‰ν•˜λ―€λ‘œ, λŒ€μš©λŸ‰μ˜ 파일 λ””μŠ€ν¬λ¦½ν„° μ§‘ν•©μ—μ„œλŠ” μ„±λŠ₯ λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.

β†˜οΈŽ poll
poll은 select와 λ§ˆμ°¬κ°€μ§€λ‘œ λΉ„νŠΈλ§΅μ„ μ‚¬μš©ν•˜μ—¬ 파일 λ””μŠ€ν¬λ¦½ν„°μ˜ μƒνƒœ λ³€ν™”λ₯Ό κ°μ‹œν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ select와 달리 파일 λ””μŠ€ν¬λ¦½ν„° 수의 μ œν•œμ΄ μ—†μœΌλ©°, μ„±λŠ₯도 select보닀 μš°μˆ˜ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ—¬μ „νžˆ 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό 순차적으둜 νƒμƒ‰ν•˜λ―€λ‘œ, λŒ€μš©λŸ‰μ˜ 파일 λ””μŠ€ν¬λ¦½ν„° μ§‘ν•©μ—μ„œλ„ μ„±λŠ₯ λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.

β†˜οΈŽ epoll
epoll은 λ¦¬λˆ…μŠ€μ—μ„œ μ‚¬μš©λ˜λŠ” I/O λ©€ν‹°ν”Œλ ‰μ‹± κΈ°λ²•μœΌλ‘œ, 이벀트 기반으둜 λ™μž‘ν•©λ‹ˆλ‹€. epoll은 select와 poll의 μ„±λŠ₯ 문제λ₯Ό κ°œμ„ ν•˜κΈ° μœ„ν•΄ κ³ μ•ˆλ˜μ—ˆμŠ΅λ‹ˆλ‹€. epoll은 μ΄λ²€νŠΈκ°€ λ°œμƒν•œ 파일 λ””μŠ€ν¬λ¦½ν„°λ§Œ λ°˜ν™˜ν•˜κΈ° λ•Œλ¬Έμ—, λŒ€μš©λŸ‰μ˜ 파일 λ””μŠ€ν¬λ¦½ν„° μ§‘ν•©μ—μ„œλ„ λΉ λ₯΄κ³  효율적으둜 이벀트λ₯Ό μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ, epoll은 수천, μˆ˜μ‹­λ§Œ 개 μ΄μƒμ˜ 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό λͺ¨λ‹ˆν„°λ§ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

β†˜οΈŽ kqueue
kqueue은 FreeBSD와 macOSμ—μ„œ μ‚¬μš©λ˜λŠ” I/O λ©€ν‹°ν”Œλ ‰μ‹± μ‹€ν–‰ 방식은 epollκ³Ό μœ μ‚¬ν•˜μ§€λ§Œ, kqueue은 epoll보닀 더 λ§Žμ€ 이벀트 μœ ν˜•μ„ μ§€μ›ν•˜κ³ , 이벀트 λ°œμƒ μ‹œ 데이터λ₯Ό λ°˜ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ, kqueue은 파일 λ””μŠ€ν¬λ¦½ν„°μ™€ λ‹€λ₯Έ λ¦¬μ†ŒμŠ€(예: ν”„λ‘œμ„ΈμŠ€, 타이머 λ“±)λ₯Ό λ™μ‹œμ— 관리할 수 μžˆμœΌλ―€λ‘œ, λ‹€μ–‘ν•œ μš©λ„λ‘œ ν™œμš©λ  수 μžˆμŠ΅λ‹ˆλ‹€. kqueue은 epoll보닀 μƒλŒ€μ μœΌλ‘œ 느릴 수 μžˆμ§€λ§Œ, 맀우 높은 μ²˜λ¦¬λŸ‰μ„ κ°–λŠ” μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œλŠ” 더 높은 μ„±λŠ₯을 λ°œνœ˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ΄λŸ¬ν•œ select, poll, epoll, kqueue의 νŠΉμ§•κ³Ό 차이점을 κ³ λ €ν•˜μ—¬, κ°œλ°œν•˜λ €λŠ” μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μš”κ΅¬μ‚¬ν•­κ³Ό 운영 체제 ν™˜κ²½μ— 따라 μ μ ˆν•œ I/O λ©€ν‹°ν”Œλ ‰μ‹± 기법을 선택할 수 μžˆμŠ΅λ‹ˆλ‹€.



πŸ…€ getaddrinfo, freeaddrinfo에 λŒ€ν•΄μ„œ μ„€λͺ…ν•΄μ£Όλ ΄

πŸ„°

getaddrinfoλŠ” 호슀트 이름과 μ„œλΉ„μŠ€ 이름(ν˜Ήμ€ 포트 번호)을 μž…λ ₯ λ°›μ•„ ν•΄λ‹Ή ν˜ΈμŠ€νŠΈμ™€ μ„œλΉ„μŠ€μ— λŒ€ν•œ μ£Όμ†Œ 정보λ₯Ό κ°€μ Έμ˜€λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€. 이 ν•¨μˆ˜λŠ” IPv4와 IPv6λ₯Ό λͺ¨λ‘ μ§€μ›ν•˜λ©°, μ—¬λŸ¬ 개의 μ£Όμ†Œ 정보λ₯Ό λ°˜ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ λ‹€μ–‘ν•œ μ£Όμ†Œ μ •λ³΄λŠ” struct addrinfo ꡬ쑰체의 ν˜•νƒœλ‘œ λ°˜ν™˜λ©λ‹ˆλ‹€.

getaddrinfo ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜κΈ° μ „μ—λŠ” λ°˜λ“œμ‹œ ν•΄λ‹Ή ꡬ쑰체λ₯Ό μ΄ˆκΈ°ν™”ν•΄μ•Ό ν•©λ‹ˆλ‹€. λ˜ν•œ, getaddrinfo ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•œ ν›„μ—λŠ” λ°˜ν™˜λœ addrinfo ꡬ쑰체λ₯Ό λ©”λͺ¨λ¦¬μ—μ„œ ν•΄μ œν•΄μ£Όμ–΄μ•Ό ν•˜λŠ”λ°, 이λ₯Ό μœ„ν•΄ freeaddrinfo ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

freeaddrinfo ν•¨μˆ˜λŠ” getaddrinfo ν•¨μˆ˜κ°€ λ°˜ν™˜ν•œ addrinfo ꡬ쑰체의 λ©”λͺ¨λ¦¬λ₯Ό ν•΄μ œν•˜λŠ” 역할을 ν•©λ‹ˆλ‹€. 이 ν•¨μˆ˜λŠ” getaddrinfo ν•¨μˆ˜κ°€ λ°˜ν™˜ν•œ addrinfo ꡬ쑰체λ₯Ό 인자둜 λ°›μ•„ ν•΄λ‹Ή ꡬ쑰체의 λ©”λͺ¨λ¦¬λ₯Ό ν•΄μ œν•˜λ©°, μ΄λ•Œ ꡬ쑰체 내뢀에 μžˆλŠ” ai_next 포인터도 μž¬κ·€μ μœΌλ‘œ ν•΄μ œν•©λ‹ˆλ‹€. 이λ₯Ό 톡해 λ©”λͺ¨λ¦¬ λˆ„μˆ˜λ₯Ό 방지할 수 μžˆμŠ΅λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄, μ•„λž˜λŠ” getaddrinfo와 freeaddrinfoλ₯Ό μ‚¬μš©ν•˜μ—¬ κ΅¬κΈ€μ˜ DNS μ„œλ²„ μ£Όμ†Œ 정보λ₯Ό κ°€μ Έμ˜€κ³  λ©”λͺ¨λ¦¬λ₯Ό ν•΄μ œν•˜λŠ” μ˜ˆμ‹œ μ½”λ“œμž…λ‹ˆλ‹€.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int main()
{
    struct addrinfo hints;
    struct addrinfo *result, *rp;
    int status;

    /* μ΄ˆκΈ°ν™” */
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC; /* IPv4 λ˜λŠ” IPv6 */
    hints.ai_socktype = SOCK_DGRAM; /* UDP μ†ŒμΌ“ */
    hints.ai_flags = AI_PASSIVE; /* 호슀트 이름이 μ—†λŠ” 경우 */

    /* κ΅¬κΈ€μ˜ DNS μ„œλ²„ μ£Όμ†Œ 정보 κ°€μ Έμ˜€κΈ° */
    status = getaddrinfo("8.8.8.8", "53", &hints, &result);
    if (status != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
        exit(EXIT_FAILURE);
    }

    /* κ°€μ Έμ˜¨ μ£Όμ†Œ 정보 좜λ ₯ */
    for (rp = result; rp != NULL; rp = rp->ai_next) {
        char host[NI_MAXHOST], service[NI_MAXSERV];
        status = getnameinfo(rp->ai_addr, rp->ai_addrlen,
                             host, NI_MAXHOST,
                             service, NI_MAXSERV,
                             NI_NUMERICHOST | NI_NUMERICSERV);
        if (status != 0) {
            fprintf(stderr, "getnameinfo: %s\n", gai_strerror(status));
            exit(EXIT_FAILURE);
        }
        printf("IP address: %s, Port number: %s\n", host, service);
    }

    /* addrinfo ꡬ쑰체의 λ©”λͺ¨λ¦¬ ν•΄μ œ */
    freeaddrinfo(result);

    return 0;
}

getaddrinfo ν•¨μˆ˜λŠ” λ‹€μŒκ³Ό 같은 λ„€ 개의 인자λ₯Ό λ°›μŠ΅λ‹ˆλ‹€.

  • node: 호슀트 이름 λ˜λŠ” IP μ£Όμ†Œλ₯Ό μ§€μ •ν•˜λŠ” λ¬Έμžμ—΄μž…λ‹ˆλ‹€. 이 μΈμžλŠ” ν•„μˆ˜μ μ΄λ©°, NULLμ΄λ‚˜ 빈 λ¬Έμžμ—΄("")을 전달할 수 μžˆμŠ΅λ‹ˆλ‹€. λ§Œμ•½ NULLμ΄λ‚˜ 빈 λ¬Έμžμ—΄("")을 μ „λ‹¬ν•œ κ²½μš°μ—λŠ” local IP μ£Όμ†Œκ°€ λ°˜ν™˜λ©λ‹ˆλ‹€.

  • service: μ„œλΉ„μŠ€ 이름 λ˜λŠ” 포트 번호λ₯Ό μ§€μ •ν•˜λŠ” λ¬Έμžμ—΄μž…λ‹ˆλ‹€. 이 μΈμžλŠ” NULLμ΄λ‚˜ 빈 λ¬Έμžμ—΄("")을 전달할 수 μžˆμŠ΅λ‹ˆλ‹€. λ§Œμ•½ NULLμ΄λ‚˜ 빈 λ¬Έμžμ—΄("")을 μ „λ‹¬ν•œ κ²½μš°μ—λŠ” 0이 λ°˜ν™˜λ©λ‹ˆλ‹€.

  • hints: struct addrinfo ꡬ쑰체의 ν¬μΈν„°μž…λ‹ˆλ‹€. 이 ꡬ쑰체λ₯Ό μ‚¬μš©ν•˜μ—¬ λ°˜ν™˜λ°›κ³ μž ν•˜λŠ” μ£Όμ†Œ μ •λ³΄μ˜ νŠΉμ„±μ„ 지정할 수 μžˆμŠ΅λ‹ˆλ‹€. 이 ꡬ쑰체λ₯Ό NULL둜 μ „λ‹¬ν•˜λŠ” 경우, getaddrinfo ν•¨μˆ˜λŠ” 기본값을 μ‚¬μš©ν•©λ‹ˆλ‹€.

  • res: struct addrinfo ꡬ쑰체의 ν¬μΈν„°μž…λ‹ˆλ‹€. 이 포인터가 κ°€λ¦¬ν‚€λŠ” κ΅¬μ‘°μ²΄μ—λŠ” getaddrinfo ν•¨μˆ˜κ°€ λ°˜ν™˜ν•œ μ£Όμ†Œ 정보가 μ €μž₯λ©λ‹ˆλ‹€. 이 포인터가 NULL인 경우, getaddrinfo ν•¨μˆ˜λŠ” λ°˜ν™˜λœ μ£Όμ†Œ 정보λ₯Ό λ¬΄μ‹œν•©λ‹ˆλ‹€.

hints ꡬ쑰체의 멀버 λ³€μˆ˜λ‘œλŠ” ai_family, ai_socktype, ai_protocol, ai_flags 등이 있으며, 이듀을 톡해 λ°˜ν™˜λ°›κ³ μž ν•˜λŠ” μ£Όμ†Œ μ •λ³΄μ˜ νŠΉμ„±μ„ 지정할 수 μžˆμŠ΅λ‹ˆλ‹€. μžμ„Έν•œ λ‚΄μš©μ€ man getaddrinfoλ₯Ό μ°Έκ³ ν•˜μ‹œκΈ° λ°”λžλ‹ˆλ‹€.



πŸ…€ setsockopt, getsockname, getprotobyname ν•¨μˆ˜μ— λŒ€ν•΄ μ„€λͺ…ν•΄μ£Όλ ¨?

πŸ„° 각 ν•¨μˆ˜μ— λŒ€ν•΄ κ°„λ‹¨ν•œ μ„€λͺ…을 λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€.

β†˜οΈŽ setsockopt
setsockopt ν•¨μˆ˜λŠ” μ†ŒμΌ“μ˜ μ˜΅μ…˜ 값을 μ„€μ •ν•©λ‹ˆλ‹€. 이 ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ μ†ŒμΌ“μ˜ μ†‘μˆ˜μ‹  버퍼 크기, λΈŒλ‘œλ“œμΊμŠ€νŠΈ κ°€λŠ₯ μ—¬λΆ€, μ†ŒμΌ“μ˜ νƒ€μž… 등을 μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€. ν•¨μˆ˜μ˜ ν”„λ‘œν† νƒ€μž…μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

#include <sys/types.h>
#include <sys/socket.h>

int setsockopt(int sockfd, int level, int optname,
               const void *optval, socklen_t optlen);
  • sockfd: μ†ŒμΌ“ 파일 λ””μŠ€ν¬λ¦½ν„°μž…λ‹ˆλ‹€.
  • level: μ˜΅μ…˜μ˜ ν”„λ‘œν† μ½œ μˆ˜μ€€μž…λ‹ˆλ‹€. 일반적으둜 SOL_SOCKET을 μ‚¬μš©ν•©λ‹ˆλ‹€.
  • optname: μ„€μ •ν•˜λ €λŠ” μ˜΅μ…˜μ˜ μ΄λ¦„μž…λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ μ†ŒμΌ“μ˜ μ†‘μˆ˜μ‹  버퍼 크기λ₯Ό μ„€μ •ν•˜λ €λ©΄ SO_SNDBUF λ˜λŠ” SO_RCVBUFλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.
  • optval: μ„€μ •ν•˜λ €λŠ” μ˜΅μ…˜ κ°’μž…λ‹ˆλ‹€.
  • optlen: optval의 ν¬κΈ°μž…λ‹ˆλ‹€.

β†˜οΈŽ getsockname
getsockname ν•¨μˆ˜λŠ” μ†ŒμΌ“μ˜ 둜컬 μ£Όμ†Œ 정보λ₯Ό μ–»μŠ΅λ‹ˆλ‹€. ν•¨μˆ˜μ˜ ν”„λ‘œν† νƒ€μž…μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

#include <sys/types.h>
#include <sys/socket.h>

int getsockname(int sockfd, struct sockaddr *addr,
                socklen_t *addrlen);
  • sockfd: μ†ŒμΌ“ 파일 λ””μŠ€ν¬λ¦½ν„°μž…λ‹ˆλ‹€.
  • addr: μ†ŒμΌ“μ˜ 둜컬 μ£Όμ†Œ 정보λ₯Ό μ €μž₯ν•  sockaddr ꡬ쑰체의 ν¬μΈν„°μž…λ‹ˆλ‹€.
  • addrlen: addr의 ν¬κΈ°μž…λ‹ˆλ‹€. ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜κΈ° 전에 이 값은 addr의 크기둜 μ΄ˆκΈ°ν™”λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

β†˜οΈŽ getprotobyname
getprotobyname ν•¨μˆ˜λŠ” ν”„λ‘œν† μ½œ 이름에 ν•΄λ‹Ήν•˜λŠ” ν”„λ‘œν† μ½œ 번호λ₯Ό μ–»μŠ΅λ‹ˆλ‹€. ν•¨μˆ˜μ˜ ν”„λ‘œν† νƒ€μž…μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

#include <netdb.h>

struct protoent *getprotobyname(const char *name);

name: ν”„λ‘œν† μ½œ μ΄λ¦„μž…λ‹ˆλ‹€. getprotobyname ν•¨μˆ˜λŠ” struct protoent ꡬ쑰체의 포인터λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. 이 κ΅¬μ‘°μ²΄μ—λŠ” ν”„λ‘œν† μ½œ 이름, ν”„λ‘œν† μ½œ 번호, ν”„λ‘œν† μ½œμ˜ λ©€ν‹°μΊμŠ€νŠΈ μ£Όμ†Œ λ“±μ˜ 정보가 μ €μž₯λ©λ‹ˆλ‹€.



πŸ…€ getprotobyname의 μ˜ˆμ‹œλ₯Ό ν•œ 번 λ³΄μ—¬μ€˜. ν”„λ‘œν† μ½œ λ²ˆν˜ΈλŠ” μ–΄λ–»κ²Œ μ–»λ‹ˆ?

πŸ„° getprotobyname ν•¨μˆ˜λŠ” ν”„λ‘œν† μ½œ 이름을 μ΄μš©ν•˜μ—¬ struct protoent ꡬ쑰체λ₯Ό μ–»μŠ΅λ‹ˆλ‹€. 이 κ΅¬μ‘°μ²΄μ—λŠ” ν”„λ‘œν† μ½œ 이름, ν”„λ‘œν† μ½œ 번호, ν”„λ‘œν† μ½œμ˜ λ©€ν‹°μΊμŠ€νŠΈ μ£Όμ†Œ λ“±μ˜ 정보가 μ €μž₯λ©λ‹ˆλ‹€. λ”°λΌμ„œ getprotobyname ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ ν”„λ‘œν† μ½œ 이름을 μ΄μš©ν•˜μ—¬ ν”„λ‘œν† μ½œ 번호λ₯Ό 얻을 수 μžˆμŠ΅λ‹ˆλ‹€.

λ‹€μŒμ€ getprotobyname ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ TCP ν”„λ‘œν† μ½œμ˜ 번호λ₯Ό μ–»λŠ” μ˜ˆμ‹œμž…λ‹ˆλ‹€.

#include <netdb.h>
#include <stdio.h>

int main() {
    struct protoent *proto = getprotobyname("tcp");

    if (proto == NULL) {
        perror("getprotobyname");
        return 1;
    }

    printf("Protocol name: %s\n", proto->p_name);
    printf("Protocol number: %d\n", proto->p_proto);
    printf("Aliases:\n");
    for (char **alias = proto->p_aliases; *alias != NULL; alias++) {
        printf("- %s\n", *alias);
    }

    return 0;
}

μœ„ μ˜ˆμ‹œλŠ” getprotobyname ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ tcp ν”„λ‘œν† μ½œμ˜ 정보λ₯Ό μ–»κ³  좜λ ₯ν•˜λŠ” μ˜ˆμ‹œμž…λ‹ˆλ‹€. μ‹€ν–‰ κ²°κ³ΌλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

Protocol name: tcp
Protocol number: 6
Aliases:
- tcp6

struct protoent ꡬ쑰체에 μ €μž₯된 정보λ₯Ό μ΄μš©ν•˜μ—¬ ν”„λ‘œν† μ½œ 번호λ₯Ό 얻을 수 μžˆμŠ΅λ‹ˆλ‹€. μœ„ μ˜ˆμ‹œμ—μ„œλŠ” proto->p_protoλ₯Ό μ΄μš©ν•˜μ—¬ tcp ν”„λ‘œν† μ½œμ˜ 번호인 6을 좜λ ₯ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.



πŸ…€ μœ„ μ˜ˆμ‹œμ—μ„œ aliasκ°€ 뭔지 μ•Œλ €μ€˜λ³΄λ ΄

πŸ„°

struct protoent κ΅¬μ‘°μ²΄μ—λŠ” ν”„λ‘œν† μ½œμ— λŒ€ν•œ λ‹€μ–‘ν•œ 정보듀이 ν¬ν•¨λ©λ‹ˆλ‹€. p_aliases λ©€λ²„λŠ” ν•΄λ‹Ή ν”„λ‘œν† μ½œμ— λŒ€ν•œ 별λͺ…(alias)λ“€μ˜ 배열을 κ°€λ¦¬ν‚€λŠ” ν¬μΈν„°μž…λ‹ˆλ‹€. 즉, ν”„λ‘œν† μ½œμ— λŒ€ν•΄ μ—¬λŸ¬ 별λͺ…이 μ‘΄μž¬ν•  경우 이 배열에 μ €μž₯λ©λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄, getprotobyname("tcp") ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜μ—¬ TCP ν”„λ‘œν† μ½œμ˜ 정보λ₯Ό 얻은 경우 proto->p_aliases λ°°μ—΄μ—λŠ” "tcp6"κ³Ό 같은 별λͺ…이 μ €μž₯될 수 μžˆμŠ΅λ‹ˆλ‹€. μœ„ μ˜ˆμ‹œμ—μ„œλŠ” μ΄λŸ¬ν•œ 별λͺ…(alias)듀을 λ°˜λ³΅λ¬Έμ„ 톡해 좜λ ₯ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.



πŸ…€ fcntl 에 λŒ€ν•΄ μ„€λͺ…해쀄 수 μžˆκ² λ‹ˆ?

πŸ„°

fcntl ν•¨μˆ˜λŠ” 파일 λ””μŠ€ν¬λ¦½ν„°μ— λŒ€ν•œ μ œμ–΄λ₯Ό μˆ˜ν–‰ν•˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€. 파일 λ””μŠ€ν¬λ¦½ν„°μ— λŒ€ν•œ μ—¬λŸ¬κ°€μ§€ λ™μž‘μ„ μˆ˜ν–‰ν•  수 있으며, 주둜 λ‹€μŒκ³Ό 같은 λͺ©μ μœΌλ‘œ μ‚¬μš©λ©λ‹ˆλ‹€.

  • 파일 λ””μŠ€ν¬λ¦½ν„°μ˜ ν”Œλž˜κ·Έ(μƒνƒœ)λ₯Ό λ³€κ²½ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, non-blocking λͺ¨λ“œλ‘œ 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 파일 λ””μŠ€ν¬λ¦½ν„°μ˜ 속성을 λ³€κ²½ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, 파일 λ””μŠ€ν¬λ¦½ν„°μ˜ close-on-exec ν”Œλž˜κ·Έλ₯Ό μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό λ™κΈ°ν™”ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, 파일 λ””μŠ€ν¬λ¦½ν„°μ˜ 락(잠금)을 μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    fcntl ν•¨μˆ˜μ˜ 기본적인 μ‚¬μš©λ²•μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.
#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */);
  • fd: 파일 λ””μŠ€ν¬λ¦½ν„°μž…λ‹ˆλ‹€.
  • cmd: μˆ˜ν–‰ν•  λ™μž‘μ„ μ§€μ •ν•˜λŠ” μ œμ–΄ λͺ…λ Ήμž…λ‹ˆλ‹€.
  • arg: μ œμ–΄ λͺ…령에 따라 μ‚¬μš©λ  μΈμžμž…λ‹ˆλ‹€.
  • fcntl ν•¨μˆ˜λŠ” μ œμ–΄ λͺ…령에 따라 arg μΈμžκ°€ ν•„μš”ν•˜μ§€ μ•Šμ„ μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ arg μΈμžλŠ” κ°€λ³€ μΈμžμž…λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄, λ‹€μŒμ€ 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό non-blocking λͺ¨λ“œλ‘œ μ„€μ •ν•˜λŠ” μ˜ˆμ‹œμž…λ‹ˆλ‹€.

#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

int set_non_blocking(int fd) {
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) {
        perror("fcntl(F_GETFL)");
        return -1;
    }

    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
        perror("fcntl(F_SETFL)");
        return -1;
    }

    return 0;
}

μœ„ μ˜ˆμ‹œμ—μ„œ fcntl(fd, F_GETFL, 0)λ₯Ό 톡해 파일 λ””μŠ€ν¬λ¦½ν„° fd의 ν”Œλž˜κ·Έλ₯Ό κ°€μ Έμ˜€κ³ , 이λ₯Ό F_SETFL μ œμ–΄ λͺ…λ Ήκ³Ό O_NONBLOCK ν”Œλž˜κ·Έλ₯Ό μ΄μš©ν•˜μ—¬ non-blocking λͺ¨λ“œλ‘œ μ„€μ •ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.



πŸ…€ fcntl(fd, F_SETFL, O_NONBLOCK) λΆ€λΆ„μ˜ 의미λ₯Ό μ’€ 더 μžμ„Έν•˜κ²Œ μ„€λͺ…ν•΄μ£Όλ ΄

πŸ„° fcntl(fd, F_SETFL, O_NONBLOCK)λŠ” 파일 λ””μŠ€ν¬λ¦½ν„° fdλ₯Ό non-blocking λͺ¨λ“œλ‘œ μ„€μ •ν•˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€.

일반적으둜, 파일 λ””μŠ€ν¬λ¦½ν„°λŠ” blocking λͺ¨λ“œλ‘œ λ™μž‘ν•©λ‹ˆλ‹€. 이 말은, 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό μ½κ±°λ‚˜ μ“Έ λ•Œ, ν•΄λ‹Ή μž‘μ—…μ΄ μ™„λ£Œλ  λ•ŒκΉŒμ§€ λŒ€κΈ°ν•˜κ²Œ λœλ‹€λŠ” λœ»μž…λ‹ˆλ‹€. μ΄λŸ¬ν•œ λŒ€κΈ° μ‹œκ°„μ€ μ‘μš© ν”„λ‘œκ·Έλž¨μ—μ„œ μ²˜λ¦¬ν•  λ‹€λ₯Έ μž‘μ—…λ“€μ„ μ§€μ—°μ‹œν‚€λŠ” 원인이 될 수 μžˆμŠ΅λ‹ˆλ‹€.

λ”°λΌμ„œ, non-blocking λͺ¨λ“œλ‘œ 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό μ„€μ •ν•˜λ©΄, ν•΄λ‹Ή 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό μ½κ±°λ‚˜ μ“Έ λ•Œ, λŒ€κΈ°ν•˜μ§€ μ•Šκ³  μ¦‰μ‹œ λ°˜ν™˜ν•˜κ²Œ λ©λ‹ˆλ‹€. μ΄λŸ¬ν•œ λ™μž‘μ€ λŒ€κ°œ select, poll, epollκ³Ό 같은 비동기 μž…μΆœλ ₯ ν•¨μˆ˜μ™€ ν•¨κ»˜ μ‚¬μš©λ©λ‹ˆλ‹€.

μœ„μ˜ μ½”λ“œμ—μ„œ fcntl ν•¨μˆ˜λŠ” fd에 λŒ€ν•œ μ œμ–΄ λͺ…λ ΉμœΌλ‘œ F_SETFL을 μ§€μ •ν•˜κ³ , O_NONBLOCK ν”Œλž˜κ·Έλ₯Ό μΆ”κ°€ν•˜μ—¬ non-blocking λͺ¨λ“œλ‘œ μ„€μ •ν•˜λ„λ‘ ν•©λ‹ˆλ‹€. F_SETFL은 파일 λ””μŠ€ν¬λ¦½ν„°μ˜ ν”Œλž˜κ·Έλ₯Ό μ„€μ •ν•˜κΈ° μœ„ν•œ μ œμ–΄ λͺ…λ Ή 쀑 ν•˜λ‚˜μ΄λ©°, O_NONBLOCK은 non-blocking λͺ¨λ“œλ₯Ό λ‚˜νƒ€λ‚΄λŠ” μƒμˆ˜μž…λ‹ˆλ‹€.

λ”°λΌμ„œ fcntl(fd, F_SETFL, O_NONBLOCK)λŠ” 파일 λ””μŠ€ν¬λ¦½ν„° fdλ₯Ό non-blocking λͺ¨λ“œλ‘œ μ„€μ •ν•˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€.



πŸ…€ fcntl(fd, F_SETFL, O_NONBLOCK)은 μ–Έμ œ -1을 λ°˜ν™˜ν•˜λ‹ˆ

πŸ„° fcntl(fd, F_SETFL, O_NONBLOCK) ν•¨μˆ˜κ°€ -1을 λ°˜ν™˜ν•˜λŠ” κ²½μš°λŠ” 일반적으둜 λ‹€μŒκ³Ό 같은 κ²½μš°μž…λ‹ˆλ‹€.

  • fdκ°€ μœ νš¨ν•˜μ§€ μ•Šμ€ 파일 λ””μŠ€ν¬λ¦½ν„°μΈ 경우
    • F_SETFL λͺ…령이 μ§€μ›λ˜μ§€ μ•ŠλŠ” 경우
  • O_NONBLOCK ν”Œλž˜κ·Έκ°€ μ§€μ›λ˜μ§€ μ•ŠλŠ” 경우
  • λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€κ°€ 이미 fdλ₯Ό non-blocking λͺ¨λ“œλ‘œ μ„€μ •ν•œ 경우

λ˜ν•œ, fcntl() ν•¨μˆ˜κ°€ μ‹€νŒ¨ν•˜λ©΄ errno μ „μ—­ λ³€μˆ˜μ— μ‹€νŒ¨ 원인이 μ €μž₯λ©λ‹ˆλ‹€. λ”°λΌμ„œ, fcntl(fd, F_SETFL, O_NONBLOCK) ν•¨μˆ˜κ°€ -1을 λ°˜ν™˜ν•  경우, errno 값을 ν™•μΈν•˜μ—¬ μ‹€νŒ¨ 원인을 νŒŒμ•…ν•  수 μžˆμŠ΅λ‹ˆλ‹€.



πŸ…€ fcntl 으둜 μ—¬λŸ¬ 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό non-blocking λͺ¨λ“œλ‘œ μ„€μ •ν•˜κ³  μ‹€ν–‰ν•˜λŠ” μ˜ˆμ‹œλ₯Ό 보여쀄 수 μžˆκ² λ‹ˆ?

πŸ„°

λ„€, λ‹Ήμ—°νžˆμš”! μ•„λž˜ μ˜ˆμ‹œ μ½”λ“œλŠ” 파일 λ””μŠ€ν¬λ¦½ν„° 0, 1, 2λ₯Ό non-blocking λͺ¨λ“œλ‘œ μ„€μ •ν•œ ν›„, select() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ 각 파일 λ””μŠ€ν¬λ¦½ν„°μ—μ„œ μž…λ ₯을 λ°›μ•„λ“€μ΄λŠ” μ˜ˆμ‹œμž…λ‹ˆλ‹€.

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>

int main()
{
    // 파일 λ””μŠ€ν¬λ¦½ν„° 0, 1, 2λ₯Ό non-blocking λͺ¨λ“œλ‘œ μ„€μ •
    int fd_flags;
    for (int i = 0; i < 3; i++) {
        fd_flags = fcntl(i, F_GETFL, 0);
        if (fd_flags == -1) {
            perror("fcntl");
            exit(1);
        }
        if (fcntl(i, F_SETFL, fd_flags | O_NONBLOCK) == -1) {
            perror("fcntl");
            exit(1);
        }
    }

    fd_set readfds;
    char buf[1024];

    while (1) {
        // select() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ μž…λ ₯을 λ°›μ•„λ“€μž„
        FD_ZERO(&readfds);
        FD_SET(0, &readfds);
        FD_SET(1, &readfds);
        FD_SET(2, &readfds);
        if (select(3, &readfds, NULL, NULL, NULL) == -1) {
            perror("select");
            exit(1);
        }

        // μž…λ ₯이 λ“€μ–΄μ˜¨ 파일 λ””μŠ€ν¬λ¦½ν„°μ—μ„œ 데이터λ₯Ό 읽음
        for (int i = 0; i < 3; i++) {
            if (FD_ISSET(i, &readfds)) {
                ssize_t nread = read(i, buf, sizeof(buf));
                if (nread == -1) {
                    perror("read");
                    exit(1);
                }
                printf("fd=%d, read %zd bytes: %.*s\n", i, nread, (int)nread, buf);
            }
        }
    }

    return 0;
}

μœ„ μ½”λ“œμ—μ„œλŠ” λ¨Όμ € 파일 λ””μŠ€ν¬λ¦½ν„° 0, 1, 2λ₯Ό non-blocking λͺ¨λ“œλ‘œ μ„€μ •ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. κ·Έ λ‹€μŒμ—λŠ” select() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ 파일 λ””μŠ€ν¬λ¦½ν„°μ—μ„œ μž…λ ₯을 받아듀이고, μž…λ ₯이 λ“€μ–΄μ˜¨ 파일 λ””μŠ€ν¬λ¦½ν„°μ—μ„œ 데이터λ₯Ό 읽어 좜λ ₯ν•©λ‹ˆλ‹€.

참고둜, μœ„ μ½”λ“œμ—μ„œλŠ” 파일 λ””μŠ€ν¬λ¦½ν„° 0, 1, 2λ₯Ό λŒ€μƒμœΌλ‘œ non-blocking λͺ¨λ“œλ₯Ό μ„€μ •ν•˜κ³  μžˆμ§€λ§Œ, μ‹€μ œλ‘œλŠ” 이 외에도 λ‹€λ₯Έ 파일 λ””μŠ€ν¬λ¦½ν„°μ— λŒ€ν•΄μ„œλ„ non-blocking λͺ¨λ“œλ₯Ό μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.



πŸ…€ select(3, &readfds, NULL, NULL, NULL) 의 μΈμžμ— λŒ€ν•΄ μ„€λͺ…ν•΄μ£Όλ ΄^^

πŸ„° select() ν•¨μˆ˜λŠ” I/O λ©€ν‹°ν”Œλ ‰μ‹±μ„ μˆ˜ν–‰ν•˜κΈ° μœ„ν•œ μ‹œμŠ€ν…œ 콜 쀑 ν•˜λ‚˜λ‘œ, μ—¬λŸ¬ 개의 파일 λ””μŠ€ν¬λ¦½ν„°μ—μ„œ 데이터λ₯Ό 읽고 μ“°λŠ” μž‘μ—…μ„ ν•œ λ²ˆμ— μ²˜λ¦¬ν•  수 있게 ν•΄μ€λ‹ˆλ‹€. select() ν•¨μˆ˜λŠ” λ‹€μŒκ³Ό 같은 ν˜•νƒœλ₯Ό 가지고 μžˆμŠ΅λ‹ˆλ‹€.

#include <sys/select.h>

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
  • nfds: 검사할 파일 λ””μŠ€ν¬λ¦½ν„° 수(+1 된 μ΅œλŒ€κ°’)
  • readfds: 읽기 κ°€λŠ₯ν•œ μƒνƒœλ₯Ό 검사할 파일 λ””μŠ€ν¬λ¦½ν„° 집합
  • writefds: μ“°κΈ° κ°€λŠ₯ν•œ μƒνƒœλ₯Ό 검사할 파일 λ””μŠ€ν¬λ¦½ν„° 집합
  • exceptfds: μ˜ˆμ™Έκ°€ λ°œμƒν•œ μƒνƒœλ₯Ό 검사할 파일 λ””μŠ€ν¬λ¦½ν„° 집합
  • timeout: select() ν•¨μˆ˜κ°€ λΈ”λ‘œν‚Ήλ˜λŠ” μ‹œκ°„μ„ μ§€μ •ν•˜λŠ” κ°’. NULL이면 λ¬΄ν•œμ • λΈ”λ‘œν‚Ήλœλ‹€.

μœ„μ˜ ν•¨μˆ˜ ν˜ΈμΆœμ—μ„œλŠ” readfds만 μ§€μ •ν•˜κ³  λ‚˜λ¨Έμ§€ μΈμžλ“€μ€ NULL을 μ „λ‹¬ν•˜μ˜€μŠ΅λ‹ˆλ‹€. μ΄λŠ” readfds 집합에 λ“±λ‘λœ 파일 λ””μŠ€ν¬λ¦½ν„° μ€‘μ—μ„œ 읽을 수 μžˆλŠ” 것이 μžˆλŠ”μ§€λ₯Ό κ²€μ‚¬ν•˜κ³ μž ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. 이와 같이 검사할 I/O μƒνƒœλ₯Ό μ„€μ •ν•˜λŠ” 뢀뢄은 λ‹€μŒκ³Ό 같은 λ°©λ²•μœΌλ‘œ μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€.

fd_set readfds;

FD_ZERO(&readfds);
FD_SET(fd1, &readfds);
FD_SET(fd2, &readfds);

λ¨Όμ € fd_set νƒ€μž…μ˜ λ³€μˆ˜ readfdsλ₯Ό μ„ μ–Έν•˜κ³ , FD_ZERO() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ readfds μ§‘ν•©μ˜ λͺ¨λ“  λΉ„νŠΈλ₯Ό 0으둜 μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€. 그리고 FD_SET() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ fd1κ³Ό fd2λΌλŠ” 두 개의 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό readfds 집합에 λ“±λ‘ν•©λ‹ˆλ‹€.

select() ν•¨μˆ˜λŠ” μ§€μ •λœ 파일 λ””μŠ€ν¬λ¦½ν„° 쀑 ν•˜λ‚˜ μ΄μƒμ˜ I/O μƒνƒœ λ³€ν™”κ°€ λ°œμƒν•  λ•ŒκΉŒμ§€ λΈ”λ‘œν‚Ήλ˜λ©°, I/O μƒνƒœ λ³€ν™”κ°€ λ°œμƒν•˜λ©΄ ν•΄λ‹Ή μƒνƒœλ₯Ό κ²€μ‚¬ν•œ ν›„ readfds에 λ“±λ‘λœ 파일 λ””μŠ€ν¬λ¦½ν„° μ€‘μ—μ„œ 읽을 수 μžˆλŠ” 것이 μžˆλŠ”μ§€λ₯Ό κ²€μ‚¬ν•˜μ—¬ 읽기 κ°€λŠ₯ν•œ μƒνƒœλ₯Ό ν™•μΈν•©λ‹ˆλ‹€. λ”°λΌμ„œ, select() ν•¨μˆ˜ 호좜 μ΄ν›„μ—λŠ” readfds에 μ„€μ •λœ 파일 λ””μŠ€ν¬λ¦½ν„° μ€‘μ—μ„œ 읽기 κ°€λŠ₯ν•œ μƒνƒœμΈ 것이 있으면 κ·Έ 파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό μ΄μš©ν•˜μ—¬ 데이터λ₯Ό 읽을 수 있게 λ©λ‹ˆλ‹€.



πŸ…€ μœ„ μ˜ˆμ‹œμ—μ„œ λ“±μž₯ν•˜λŠ” FD_ZERO(&readfds), FD_SET(0, &readfds), FD_ISSET(i, &readfds)듀은 ν•¨μˆ˜λ‹ˆ?

πŸ„° λ„€, λ§žμŠ΅λ‹ˆλ‹€.

  • FD_ZERO(&readfds): readfds 집합을 μ΄ˆκΈ°ν™”ν•˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€. readfds 집합 λ‚΄μ˜ λͺ¨λ“  파일 λ””μŠ€ν¬λ¦½ν„°λ₯Ό μ œκ±°ν•˜κ³  초기 μƒνƒœλ‘œ λ§Œλ“­λ‹ˆλ‹€.
  • FD_SET(0, &readfds): 파일 λ””μŠ€ν¬λ¦½ν„° 0을 readfds 집합에 μΆ”κ°€ν•˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€. 이 경우 파일 λ””μŠ€ν¬λ¦½ν„° 0은 ν‘œμ€€ μž…λ ₯을 λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
  • FD_ISSET(i, &readfds): 파일 λ””μŠ€ν¬λ¦½ν„° iκ°€ readfds 집합에 ν¬ν•¨λ˜μ–΄ μžˆλŠ”μ§€ μ—¬λΆ€λ₯Ό ν™•μΈν•˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€. λ°˜ν™˜κ°’μ€ 0 λ˜λŠ” 1μž…λ‹ˆλ‹€.



πŸ…€ fdκ°€ 읽을 수 μžˆλŠ” μƒνƒœμΈμ§€ κ²€μ¦ν•˜λŠ” μ½”λ“œμ˜ μ˜ˆμ‹œλ₯Ό 보여주렴^^

πŸ„°

fdκ°€ 읽을 수 μžˆλŠ” μƒνƒœμΈμ§€ κ²€μ¦ν•˜λŠ” μ½”λ“œλŠ” λ‹€μŒκ³Ό 같이 μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>

int main(void) {
    fd_set rfds;
    struct timeval tv;
    int retval;

    // 파일 λ””μŠ€ν¬λ¦½ν„° 0을 λͺ¨λ‹ˆν„°λ§ν•˜κΈ° μœ„ν•΄ rfds 집합 μ΄ˆκΈ°ν™”
    FD_ZERO(&rfds);
    FD_SET(0, &rfds);

    // 타이머 μ„€μ •
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    // 파일 λ””μŠ€ν¬λ¦½ν„° 0이 읽을 수 μžˆλŠ” μƒνƒœκ°€ 될 λ•ŒκΉŒμ§€ λŒ€κΈ°
    retval = select(1, &rfds, NULL, NULL, &tv);
    if (retval == -1) {
        perror("select()");
        exit(EXIT_FAILURE);
    } else if (retval) {
        printf("Data is available now.\n");
    } else {
        printf("No data within five seconds.\n");
    }

    return 0;
}

μœ„ μ½”λ“œμ—μ„œ FD_ZERO ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ rfds 집합을 μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€. 그리고 FD_SET ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ 파일 λ””μŠ€ν¬λ¦½ν„° 0 (ν‘œμ€€ μž…λ ₯)을 rfds 집합에 μΆ”κ°€ν•©λ‹ˆλ‹€. 이제 select ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜μ—¬ rfds 집합에 ν¬ν•¨λœ 파일 λ””μŠ€ν¬λ¦½ν„° μ€‘μ—μ„œ 읽을 수 μžˆλŠ” μƒνƒœκ°€ 되기λ₯Ό κΈ°λ‹€λ¦½λ‹ˆλ‹€. select ν•¨μˆ˜μ˜ λ§ˆμ§€λ§‰ 인자 &tvλŠ” select ν•¨μˆ˜κ°€ μ΅œλŒ€ λͺ‡ 초 λ™μ•ˆ λŒ€κΈ°ν•΄μ•Ό ν•˜λŠ”μ§€λ₯Ό μ§€μ •ν•©λ‹ˆλ‹€. select ν•¨μˆ˜λŠ” rfds 집합에 μžˆλŠ” 파일 λ””μŠ€ν¬λ¦½ν„° μ€‘μ—μ„œ 읽을 수 μžˆλŠ” μƒνƒœκ°€ 되면 1을 λ°˜ν™˜ν•©λ‹ˆλ‹€. λ§Œμ•½ νƒ€μž„μ•„μ›ƒμ΄ λ°œμƒν•˜λ©΄ 0을 λ°˜ν™˜ν•©λ‹ˆλ‹€. 그리고 μ—λŸ¬κ°€ λ°œμƒν•˜λ©΄ -1을 λ°˜ν™˜ν•˜κ³  perror ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜μ—¬ μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό 좜λ ₯ν•©λ‹ˆλ‹€.