select_tut(2) - wariua/manpages-ko GitHub Wiki

NAME

select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - ๋™๊ธฐ์  I/O ๋‹ค์ค‘ํ™”

SYNOPSIS

/* POSIX.1-2001, POSIX.1-2008์— ๋”ฐ๋ฅด๋ฉด */
#include <sys/select.h>

/* ์ด์ „ ํ‘œ์ค€๋“ค์— ๋”ฐ๋ฅด๋ฉด */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *utimeout);

void FD_CLR(int fd, fd_set *set);
int  FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);

#include <sys/select.h>

int pselect(int nfds, fd_set *readfds, fd_set *writefds,
            fd_set *exceptfds, const struct timespec *ntimeout,
            const sigset_t *sigmask);

glibc ๊ธฐ๋Šฅ ํ™•์ธ ๋งคํฌ๋กœ ์š”๊ฑด (feature_test_macros(7) ์ฐธ๊ณ ):

pselect():
_POSIX_C_SOURCE >= 200112L

DESCRIPTION

select()๋ฅผ (๋˜๋Š” pselect()๋ฅผ) ์ด์šฉํ•ด ์—ฌ๋Ÿฌ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ฐ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ ์ค‘ ์ผ๋ถ€๊ฐ€ "์ค€๋น„" ์ƒํƒœ๊ฐ€ ๋๋Š”์ง€, ์ฆ‰ I/O๊ฐ€ ๊ฐ€๋Šฅํ•ด์กŒ๊ฑฐ๋‚˜ ๊ทธ ์ค‘ ์ผ๋ถ€์—์„œ "์˜ˆ์™ธ์ ์ธ ์ƒํ™ฉ"์ด ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ์•Œ์•„๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ฃผ๋œ ์ธ์ž๋Š” ์„ธ ๊ฐ€์ง€ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ "์ง‘ํ•ฉ"์ธ readfds, writefds, exceptfds์ด๋‹ค. ๊ฐ ์ง‘ํ•ฉ์€ fd_set ํƒ€์ž…์œผ๋กœ ์„ ์–ธํ•˜๋ฉฐ ๋งคํฌ๋กœ FD_CLR(), FD_ISSET(), FD_SET(), FD_ZERO()๋กœ ๊ทธ ๋‚ด์šฉ์„ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ƒˆ๋กœ ์ง‘ํ•ฉ์„ ์„ ์–ธํ•˜๋ฉด ๋จผ์ € FD_ZERO()๋กœ ๋น„์šฐ๋Š” ๊ฒŒ ์ข‹๋‹ค. select()์—์„œ ์•„๋ž˜์— ๊ธฐ์ˆ ํ•˜๋Š” ๊ทœ์น™์— ๋”ฐ๋ผ ์ง‘ํ•ฉ์˜ ๋‚ด์šฉ์„ ๋ณ€๊ฒฝํ•˜๋ฉฐ, select() ํ˜ธ์ถœ ํ›„์— FD_ISSET() ๋งคํฌ๋กœ๋ฅผ ์ด์šฉํ•ด ์ง‘ํ•ฉ์— ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๊ฐ€ ๊ณ„์† ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ง€์ •ํ•œ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๊ฐ€ ์ง‘ํ•ฉ ์•ˆ์— ์žˆ์œผ๋ฉด FD_ISSET()์ด 0 ์•„๋‹Œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์—†์œผ๋ฉด 0์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. FD_CLR()๋Š” ์ง‘ํ•ฉ์—์„œ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ๋บ€๋‹ค.

์ธ์ž

readfds
ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋“ค ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์ฝ๊ธฐ ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ๋ณด๊ธฐ ์œ„ํ•ด ์ด ์ง‘ํ•ฉ์„ ๊ฐ์‹œํ•œ๋‹ค. select() ๋ฐ˜ํ™˜ ํ›„์— readfds์—๋Š” ์ฆ‰์‹œ ์ฝ๊ธฐ๊ฐ€ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์€ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋“ค์ด ๋ชจ๋‘ ์ง€์›Œ์ ธ ์žˆ๊ฒŒ ๋œ๋‹ค.
writefds
ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋“ค ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๋ฐ์ดํ„ฐ๋ฅผ ์“ธ ๊ณต๊ฐ„์ด ์žˆ๋Š”์ง€ ๋ณด๊ธฐ ์œ„ํ•ด ์ด ์ง‘ํ•ฉ์„ ๊ฐ์‹œํ•œ๋‹ค. select() ๋ฐ˜ํ™˜ ํ›„์— writefds์—๋Š” ์ฆ‰์‹œ ์“ฐ๊ธฐ๊ฐ€ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์€ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋“ค์ด ๋ชจ๋‘ ์ง€์›Œ์ ธ ์žˆ๊ฒŒ ๋œ๋‹ค.
exceptfds
"์˜ˆ์™ธ์  ์ƒํ™ฉ"์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ด ์ง‘ํ•ฉ์„ ๊ฐ์‹œํ•œ๋‹ค. ์‹ค๋ฌด์—์„œ ์œ ์ผํ•œ ๊ทธ๋Ÿฐ ์˜ˆ์™ธ์  ์ƒํ™ฉ์€ ๊ฝค ํ”ํ•œ๋ฐ, ๋ฐ”๋กœ TCP ์†Œ์ผ“์—์„œ ๋Œ€์—ญ์™ธ(OOB) ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์ด๋‹ค. OOB ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ recv(2), send(2), tcp(7)๋ฅผ ๋ณด๋ผ. (select(2)์—์„œ ์˜ˆ์™ธ ์ƒํ™ฉ์ด๋ผ๊ณ  ๋‚˜ํƒ€๋‚ด๋Š” ๋œ ํ”ํ•œ ๋˜ ๋‹ค๋ฅธ ๊ฒฝ์šฐ๋Š” ํŒจํ‚ท ๋ชจ๋“œ ์œ ์‚ฌ ํ„ฐ๋ฏธ๋„์—์„œ ๋ฐœ์ƒํ•œ๋‹ค. ioctl_tty(2) ์ฐธ๊ณ .) select() ๋ฐ˜ํ™˜ ํ›„์— exceptfds์—๋Š” ์˜ˆ์™ธ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์€ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋“ค์ด ๋ชจ๋‘ ์ง€์›Œ์ ธ ์žˆ๊ฒŒ ๋œ๋‹ค.
nfds
์ง‘ํ•ฉ๋“ค์— ์žˆ๋Š” ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ ์ค‘ ๊ฐ€์žฅ ํฐ ๊ฐ’์— 1์„ ๋”ํ•œ ์ •์ˆ˜์ด๋‹ค. ๋‹ฌ๋ฆฌ ๋งํ•˜๋ฉด ์ง‘ํ•ฉ ๊ฐ๊ฐ์— ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด์„œ ๊ทธ ์ค‘ ์ตœ๋Œ€์ธ ์ •์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•œ ๋‹ค์Œ 1๋งŒํผ ์˜ฌ๋ฆฐ ๊ฐ’์„ nfds๋กœ ์ „๋‹ฌํ•˜๋ฉด ๋œ๋‹ค.
utimeout

๋ญ”๊ฐ€ ํŠน๋ณ„ํ•œ ์ผ์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋”๋ผ๋„ select()๊ฐ€ ๋ฐ˜ํ™˜ ์ „์— ์ตœ๋Œ€ ์ด ์‹œ๊ฐ„๋งŒํผ ๋Œ€๊ธฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฐ’์„ NULL๋กœ ์ „๋‹ฌํ•˜๋ฉด ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๊ฐ€ ์ค€๋น„ ์ƒํƒœ๊ฐ€ ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉฐ select()๊ฐ€ ๋ฌดํ•œ์ • ๋ธ”๋ก ํ•œ๋‹ค. utimeout์„ 0์ดˆ๋กœ ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ๋Š”๋ฐ, ๊ทธ๋Ÿฌ๋ฉด select()๊ฐ€ ํ˜ธ์ถœ ์‹œ์ ์˜ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ ์ค€๋น„ ์ƒํƒœ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์ฆ‰์‹œ ๋ฐ˜ํ™˜ํ•œ๋‹ค. struct timeval ๊ตฌ์กฐ์ฒด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜๋ผ ์žˆ๋‹ค.

struct timeval {
    time_t tv_sec;    /* ์ดˆ */
    long tv_usec;     /* ๋งˆ์ดํฌ๋กœ์ดˆ */
};
ntimeout

pselect()์˜ ์ด ์ธ์ž๋Š” utimeout๊ณผ ์˜๋ฏธ๊ฐ€ ๊ฐ™๋˜ ๋‹ค์Œ๊ณผ ๊ฐ™์ด struct timespec์˜ ์ •๋ฐ€๋„๊ฐ€ ๋‚˜๋…ธ์ดˆ์ด๋‹ค.

struct timespec {
    long tv_sec;    /* ์ดˆ */
    long tv_nsec;   /* ๋‚˜๋…ธ์ดˆ */
};
sigmask
์ด ์ธ์ž๋Š” ํ˜ธ์ถœ์ž๊ฐ€ pselect() ํ˜ธ์ถœ ๋‚ด์— ๋ธ”๋ก ๋˜์–ด ์žˆ๋Š” ๋™์•ˆ ์ปค๋„์—์„œ ์ฐจ๋‹จ์„ ํ’€์–ด์•ผ ํ•˜๋Š” (์ฆ‰ ํ˜ธ์ถœ ์Šค๋ ˆ๋“œ์˜ ์‹œ๊ทธ๋„ ๋งˆ์Šคํฌ์—์„œ ๋นผ์•ผ ํ•˜๋Š”) ์‹œ๊ทธ๋„๋“ค์˜ ์ง‘ํ•ฉ์„ ๋‹ด๋Š”๋‹ค. (sigaddset(3) ๋ฐ sigprocmask(2) ์ฐธ๊ณ .) NULL์ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ทธ๋•Œ๋Š” ํ•จ์ˆ˜์— ๋“ค์–ด๊ฐ€๊ณ  ๋‚˜์˜ฌ ๋•Œ ์‹œ๊ทธ๋„ ๋งˆ์Šคํฌ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด ๊ฒฝ์šฐ pselect()๋Š” ๊ทธ๋ƒฅ select()์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๊ฒŒ ๋œ๋‹ค.

์‹œ๊ทธ๋„๊ณผ ๋ฐ์ดํ„ฐ ์ด๋ฒคํŠธ ๋ณ‘ํ–‰ํ•˜๊ธฐ

ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๊ฐ€ I/O ์ค€๋น„๊ฐ€ ๋˜๋Š” ๊ฒƒ๋ฟ ์•„๋‹ˆ๋ผ ์‹œ๊ทธ๋„๋„ ํ•จ๊ป˜ ๊ธฐ๋‹ค๋ฆด ๋•Œ pselect()๊ฐ€ ์œ ์šฉํ•˜๋‹ค. ์‹œ๊ทธ๋„์„ ๋ฐ›๋Š” ํ”„๋กœ๊ทธ๋žจ๋“ค์€ ๋ณดํ†ต ์‹œ๊ทธ๋„ ํ•ธ๋“ค๋Ÿฌ์—์„œ ์ „์—ญ ํ”Œ๋ž˜๊ทธ์— ํ‘œ์‹œ๋งŒ ํ•ด ๋‘”๋‹ค. ๊ทธ ์ „์—ญ ํ”Œ๋ž˜๊ทธ๋Š” ํ”„๋กœ๊ทธ๋žจ ๋ฉ”์ธ ๋ฃจํ”„์—์„œ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค๋Š” ํ‘œ์‹œ์ด๋‹ค. ์‹œ๊ทธ๋„์ด ์ „๋‹ฌ๋˜๋ฉด select() (๋˜๋Š” pselect()) ํ˜ธ์ถœ์ด errno์— EINTR๋ฅผ ์„ค์ •ํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋œ๋‹ค. ์ด๋ ‡๊ฒŒ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด select()๊ฐ€ ๋ฌดํ•œ์ • ๋ธ”๋ก ํ•  ์ˆ˜๋„ ์žˆ์œผ๋ฏ€๋กœ ์ด ๋™์ž‘ ๋ฐฉ์‹์€ ํ”„๋กœ๊ทธ๋žจ ๋ฉ”์ธ ๋ฃจํ”„์—์„œ ์‹œ๊ทธ๋„์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ๊ผญ ํ•„์š”ํ•˜๋‹ค. ์ด์ œ ๋ฉ”์ธ ๋ฃจํ”„ ๋‚ด์˜ ์–ด๋”˜๊ฐ€์— ์กฐ๊ฑด๋ฌธ์ด ์žˆ์–ด์„œ ๊ทธ ์ „์—ญ ํ”Œ๋ž˜๊ทธ๋ฅผ ํ™•์ธํ•  ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ์กฐ๊ฑด๋ฌธ ๋‹ค์Œ์—, ๊ทธ๋Ÿฌ๋ฉด์„œ select() ํ˜ธ์ถœ ์ „์— ์‹œ๊ทธ๋„์ด ๋„์ฐฉํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ๋‹ต์€, ์ฒ˜๋ฆฌ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๋ถ„๋ช… ์žˆ๋Š”๋ฐ๋„ select()๊ฐ€ ๋ฌดํ•œ์ • ๋ธ”๋ก ํ•˜๊ฒŒ ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์ด ๊ฒฝ์Ÿ ์กฐ๊ฑด์„ ํ•ด๊ฒฐํ•ด ์ฃผ๋Š” ๊ฒƒ์ด pselect() ํ˜ธ์ถœ์ด๋‹ค. ์ด ํ˜ธ์ถœ์„ ์‚ฌ์šฉํ•˜๋ฉด pselect() ํ˜ธ์ถœ ๋‚ด์—์„œ๋งŒ ์ˆ˜์‹ ํ•  ์‹œ๊ทธ๋„๋“ค์„ ๊ทธ ์‹œ๊ทธ๋„ ๋งˆ์Šคํฌ์— ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฌธ์ œ์˜ ์ด๋ฒคํŠธ๊ฐ€ ์ž์‹ ํ”„๋กœ์„ธ์Šค ์ข…๋ฃŒ๋ผ๊ณ  ํ•˜์ž. ์ผ๋‹จ ๋ฉ”์ธ ๋ฃจํ”„ ์‹œ์ž‘ ์ „์— sigprocmask(2)๋ฅผ ์ด์šฉํ•ด SIGCHLD๋ฅผ ๋ง‰์•„ ๋‘”๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋นˆ ์‹œ๊ทธ๋„ ๋งˆ์Šคํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด pselect()์—์„œ SIGCHLD๋ฅผ ํ™œ์„ฑํ™”ํ•œ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ”„๋กœ๊ทธ๋žจ์ด ๋  ๊ฒƒ์ด๋‹ค.

static volatile sig_atomic_t got_SIGCHLD = 0;

static void
child_sig_handler(int sig)
{
    got_SIGCHLD = 1;
}

int
main(int argc, char *argv[])
{
    sigset_t sigmask, empty_mask;
    struct sigaction sa;
    fd_set readfds, writefds, exceptfds;
    int r;

    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGCHLD);
    if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1) {
        perror("sigprocmask");
        exit(EXIT_FAILURE);
    }

    sa.sa_flags = 0;
    sa.sa_handler = child_sig_handler;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }

    sigemptyset(&empty_mask);

    for (;;) {          /* ๋ฉ”์ธ ๋ฃจํ”„ */
        /* pselect() ํ˜ธ์ถœ ์ „์— readfds, writefds,
           exceptfds๋ฅผ ์„ค์ •ํ•œ๋‹ค. (์ฝ”๋“œ ์ƒ๋žต) */

        r = pselect(nfds, &readfds, &writefds, &exceptfds,
                    NULL, &empty_mask);
        if (r == -1 && errno != EINTR) {
            /* ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ */
        }

        if (got_SIGCHLD) {
            got_SIGCHLD = 0;

            /* ์‹œ๊ทธ๋„๋กœ ๋ฐ›์€ ์ด๋ฒคํŠธ๋ฅผ ์—ฌ๊ธฐ์„œ ์ฒ˜๋ฆฌ.
               ๊ฐ€๋ น ์ข…๋ฃŒํ•œ ์ž์‹๋“ค wait() ํ•˜๊ธฐ. (์ฝ”๋“œ ์ƒ๋žต) */
        }

        /* ํ”„๋กœ๊ทธ๋žจ ์ฃผ ์ž‘์—… */
    }
}

์‹ค์šฉ์„ฑ

๊ทผ๋ฐ select()๊ฐ€ ์™œ ์žˆ๋Š” ๊ฑธ๊นŒ? ๊ทธ๋ƒฅ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ์—์„œ ์ฝ๊ธฐ์™€ ์“ฐ๊ธฐ๋ฅผ ํ•˜๋ฉด ์•ˆ ๋ ๊นŒ? select()์˜ ํ•ต์‹ฌ์€ ๋™์‹œ์— ์—ฌ๋Ÿฌ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ๊ฐ์‹œํ•˜๊ณ  ์•„๋ฌด ํ™œ๋™์ด ์—†์œผ๋ฉด ์˜ฌ๋ฐ”๋กœ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ž ๋“ค๊ฒŒ ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค. ์œ ๋‹‰์Šค ํ”„๋กœ๊ทธ๋ž˜๋จธ๋“ค์€ ์ข…์ข… ๋ฐ์ดํ„ฐ ํ๋ฆ„์ด ๊ฐ„ํ—์ ์ธ ์—ฌ๋Ÿฌ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋“ค์—์„œ I/O ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค. ๋‹จ์ˆœํžˆ read(2)์™€ write(2)๋ฅผ ์ฐจ๋ก€๋กœ ํ˜ธ์ถœํ•˜๊ธฐ๋งŒ ํ•œ๋‹ค๋ฉด ์–ด๋–ค ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ์— ๋Œ€๊ธฐํ•˜๋ฉฐ ํ˜ธ์ถœ์ด ๋ธ”๋กํ•˜๊ณ  ์žˆ๋Š” ๋™์•ˆ ๋‹ค๋ฅธ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๊ฐ€ I/O ์ค€๋น„ ์ƒํƒœ์ธ๋ฐ๋„ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๋ณด๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค. select()๋กœ ๊ทธ๋Ÿฐ ์ƒํ™ฉ์— ํšจ์œจ์ ์œผ๋กœ ๋Œ€์ฒ˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

์„ ํƒ ๊ทœ์น™

select()๋ฅผ ์จ ๋ณด๋ ค๋Š” ๋งŽ์€ ์ด๋“ค์€ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์šฐ๋ฉฐ ์ด์‹์„ฑ์ด ์—†๊ฑฐ๋‚˜ ์˜ค๋ฝ๊ฐ€๋ฝํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋†“๋Š” ๋™์ž‘ ๋ฐฉ์‹์— ๋ถ€๋‹ฅ์นœ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์œ„ ํ”„๋กœ๊ทธ๋žจ์€ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ๋…ผ๋ธ”๋กœํ‚น ๋ชจ๋“œ๋กœ ์„ค์ •ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ์–ด๋А ์ง€์ ์—์„œ๋„ ๋ธ”๋ก ํ•˜์ง€ ์•Š๋„๋ก ์กฐ์‹ฌ์Šค๋Ÿฝ๊ฒŒ ์ž‘์„ฑ๋œ ๊ฒƒ์ด๋‹ค. ์ž์นซํ•˜๋ฉด select()๋ฅผ ์“ฐ๋Š” ์žฅ์ ์„ ์—†์•  ๋ฒ„๋ฆฌ๋Š” ๋ฏธ๋ฌ˜ํ•œ ์˜ค๋ฅ˜๋ฅผ ๋งŒ๋“ค๊ฒŒ ๋˜๊ธฐ ์‰ฌ์šฐ๋ฏ€๋กœ select() ์‚ฌ์šฉ ์‹œ ์ฃผ์˜ํ•ด์•ผ ํ•  ํ•ต์‹ฌ ์‚ฌํ•ญ๋“ค์„ ์—ฌ๊ธฐ ๋‚˜์—ดํ•œ๋‹ค.

  1. ๊ฐ€๊ธ‰์  select()๋ฅผ ํƒ€์ž„์•„์›ƒ ์—†์ด ์“ฐ๋Š” ๊ฒŒ ์ข‹๋‹ค. ๊ฐ€์šฉ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด ํ”„๋กœ๊ทธ๋žจ์—์„œ ํ•  ์ผ์ด ์—†์–ด์•ผ ํ•œ๋‹ค. ํƒ€์ž„์•„์›ƒ์— ์˜์กดํ•˜๋Š” ์ฝ”๋“œ๋Š” ํ•ญ์ƒ ์ด์‹ ๊ฐ€๋Šฅํ•˜์ง€๋Š” ์•Š์œผ๋ฉฐ ๋””๋ฒ„๊ทธ ํ•˜๊ธฐ ์–ด๋ ต๋‹ค.

  2. ํšจ์œจ์„ฑ์„ ์œ„ํ•ด nfds์˜ ๊ฐ’์„ ์œ„์— ์„ค๋ช…ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์˜ฌ๋ฐ”๋กœ ๊ณ„์‚ฐํ•ด์•ผ ํ•œ๋‹ค.

  3. select() ํ˜ธ์ถœ ํ›„์— ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด์„œ ์ ์ ˆํžˆ ๋Œ€์‘ํ•  ๊ฒŒ ์•„๋‹ˆ๋ผ๋ฉด ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ์•„๋ฌด ์ง‘ํ•ฉ์—๋„ ์ถ”๊ฐ€ํ•˜์ง€ ๋งˆ๋ผ. ๋‹ค์Œ ๊ทœ์น™ ์ฐธ๊ณ .

  4. select() ๋ฐ˜ํ™˜ ํ›„์— ๋ชจ๋“  ์ง‘ํ•ฉ์˜ ๋ชจ๋“  ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋“ค์„ ํ™•์ธํ•˜๋Š” ๊ฒŒ ์ข‹๋‹ค.

  5. read(2), recv(2), write(2), send(2) ํ•จ์ˆ˜๊ฐ€ ๊ผญ ์š”์ฒญ ๋ฐ์ดํ„ฐ ๋ชจ๋‘๋ฅผ ์ฝ๋Š”/์“ฐ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์ „์ฒด๋ฅผ ์ฝ๋Š”๋‹ค๋ฉด/์“ด๋‹ค๋ฉด ๊ทธ๊ฑด ํŠธ๋ž˜ํ”ฝ ๋ถ€ํ•˜๊ฐ€ ์ž‘๊ณ  ์ŠคํŠธ๋ฆผ์ด ๋น ๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํ•ญ์ƒ ๊ทธ๋ ‡์ง€๋Š” ์•Š๋‹ค. ํ•จ์ˆ˜์—์„œ ํ•œ ๋ฐ”์ดํŠธ๋งŒ ๊ฒจ์šฐ ๋ณด๋‚ด๊ฑฐ๋‚˜ ๋ฐ›๋Š” ๊ฒฝ์šฐ์— ๋Œ€์ฒ˜ํ•ด์•ผ ํ•œ๋‹ค.

  6. ์ฒ˜๋ฆฌํ•  ๋ฐ์ดํ„ฐ๊ฐ€ ์ •๋ง ์กฐ๊ธˆ๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ฉด ์ ˆ๋Œ€ ํ•œ๋ฒˆ์— ํ•œ ๋ฐ”์ดํŠธ์”ฉ ์ฝ์ง€/์“ฐ์ง€ ๋งˆ๋ผ. ๋ฒ„ํผ๋ฅผ ์ตœ๋Œ€ํ•œ ์ฑ„์›Œ์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์ง€/์“ฐ์ง€ ์•Š์œผ๋ฉด ๋งค์šฐ ๋น„ํšจ์œจ์ ์œผ๋กœ ๋œ๋‹ค. ์•„๋ž˜ ์˜ˆ์˜ ๋ฒ„ํผ๋“ค์€ 1024๋ฐ”์ดํŠธ์ง€๋งŒ ์†์‰ฝ๊ฒŒ ํฌ๊ธฐ๋ฅผ ํ‚ค์šธ ์ˆ˜ ์žˆ๋‹ค.

  7. read(2), recv(2), write(2), send(2), select() ํ˜ธ์ถœ์ด EINTR ์˜ค๋ฅ˜๋กœ ์‹คํŒจํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ read(2), recv(2), write(2), send(2) ํ˜ธ์ถœ์ด ์‹คํŒจํ•ด์„œ errno์— EAGAIN(EWOULDBLOCK)์ด ์„ค์ •๋  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ๋“ค์„ ์ œ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค. (์œ„์—์„œ๋Š” ๊ทธ๋Ÿฌ์ง€ ์•Š์•˜๋‹ค.) ํ”„๋กœ๊ทธ๋žจ์ด ์–ด๋–ค ์‹œ๊ทธ๋„๋„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค๋ฉด ์•„๋งˆ EINTR๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค. ํ”„๋กœ๊ทธ๋žจ์—์„œ ๋…ผ๋ธ”๋กœํ‚น I/O๋ฅผ ์„ค์ •ํ•˜์ง€ ์•Š์œผ๋ฉด EAGAIN์ด ๋‚˜์˜ค์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค.

  8. ์ ˆ๋Œ€๋กœ ๋ฒ„ํผ ๊ธธ์ด๋ฅผ 0์œผ๋กœ ํ•ด์„œ read(2), recv(2), write(2), send(2)๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ๋งˆ๋ผ.

  9. ํ•จ์ˆ˜ read(2), recv(2), write(2), send(2)๊ฐ€ 7๋ฒˆ์— ๋‚˜์—ดํ•œ ๊ฒƒ ์™ธ์˜ ์˜ค๋ฅ˜๋กœ ์‹คํŒจํ•˜๊ฑฐ๋‚˜ ์ž…๋ ฅ ํ•จ์ˆ˜๋“ค์ด ํŒŒ์ผ ๋์„ ๋‚˜ํƒ€๋‚ด๋Š” 0์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ๊ทธ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ select()๋กœ ๋‹ค์‹œ ์ „๋‹ฌํ•˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค. ์œ„ ์˜ˆ์—์„œ๋Š” ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ์ฆ‰์‹œ ๋‹ซ๊ณ ์„œ -1๋กœ ์„ค์ •ํ•ด์„œ ์ง‘ํ•ฉ์— ํฌํ•จ๋˜๋Š” ๊ฑธ ๋ฐฉ์ง€ํ•œ๋‹ค.

  10. select()๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ํƒ€์ž„์•„์›ƒ ๊ฐ’์„ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค. ์ผ๋ถ€ ์šด์˜ ์ฒด์ œ์—์„œ ๊ทธ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํ•˜์ง€๋งŒ pselect()์—์„œ๋Š” ํƒ€์ž„์•„์›ƒ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค.

  11. select()์—์„œ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ ์ง‘ํ•ฉ๋“ค์„ ๋ณ€๊ฒฝํ•˜๋ฏ€๋กœ ๋ฃจํ”„ ์•ˆ์—์„œ ํ˜ธ์ถœ์„ ํ•˜๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด ํ˜ธ์ถœ ์ „์— ๋งค๋ฒˆ ์ง‘ํ•ฉ๋“ค์„ ๋‹ค์‹œ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค.

usleep ์—๋ฎฌ๋ ˆ์ด์…˜

usleep(3) ํ•จ์ˆ˜๊ฐ€ ์—†๋Š” ์‹œ์Šคํ…œ์—์„œ๋Š” ๋‹ค์Œ์ฒ˜๋Ÿผ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ ์—†์ด ์ •ํ•ด์ง„ ํƒ€์ž„์•„์›ƒ์œผ๋กœ select()๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 200000;  /* 0.2 ์ดˆ */
select(0, NULL, NULL, NULL, &tv);

๋‹ค๋งŒ ์œ ๋‹‰์Šค ์‹œ์Šคํ…œ๋“ค์—์„œ๋งŒ ๋™์ž‘์ด ๋ณด์žฅ๋œ๋‹ค.

RETURN VALUE

์„ฑ๊ณต ์‹œ select()๋Š” ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ ์ง‘ํ•ฉ๋“ค์— ์•„์ง ์žˆ๋Š” ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋“ค์˜ ์ด๊ฐœ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

select()๊ฐ€ ํƒ€์ž„์•„์›ƒ ๋˜๋ฉด ๋ฐ˜ํ™˜ ๊ฐ’์ด 0์ด ๋œ๋‹ค. ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ ์ง‘ํ•ฉ์ด ๋ชจ๋‘ ๋น„์–ด ์žˆ์„ ๊ฒƒ์ด๋‹ค. (ํ•˜์ง€๋งŒ ์–ด๋–ค ์‹œ์Šคํ…œ์—์„œ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ๋‹ค.)

๋ฐ˜ํ™˜ ๊ฐ’ -1์€ ์˜ค๋ฅ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋ฉฐ errno๊ฐ€ ์ ์ ˆํžˆ ์„ค์ •๋œ๋‹ค. ์˜ค๋ฅ˜ ๊ฒฝ์šฐ์— ๋ฐ˜ํ™˜๋œ ์ง‘ํ•ฉ๋“ค์˜ ๋‚ด์šฉ๊ณผ struct timeout์˜ ๋‚ด์šฉ์€ ๊ทœ์ •๋ผ ์žˆ์ง€ ์•Š์œผ๋ฏ€๋กœ ์‚ฌ์šฉํ•˜์ง€ ๋ง์•„์•ผ ํ•œ๋‹ค. ๋‹ค๋งŒ pselect()์—์„œ๋Š” ์ ˆ๋Œ€ ntimeout์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค.

NOTES

์ผ๋ฐ˜์ ์œผ๋กœ ๋งํ•ด์„œ ์†Œ์ผ“์„ ์ง€์›ํ•˜๋Š” ์šด์˜ ์ฒด์ œ๋“ค์€ ๋ชจ๋‘ select()๋„ ์ง€์›ํ•œ๋‹ค. select()๋ฅผ ์“ฐ๋ฉด ์ดˆ๋ณด ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ์Šค๋ ˆ๋“œ, ํฌํฌ, IPC, ์‹œ๊ทธ๋„, ๋ฉ”๋ชจ๋ฆฌ ๊ณต์œ  ๋“ฑ์„ ์ด์šฉํ•ด ๋ณต์žกํ•˜๊ฒŒ ํ•ด๊ฒฐํ•˜๋ ค ํ•˜๋Š” ์—ฌ๋Ÿฌ ๋ฌธ์ œ๋“ค์„ ์ด์‹์„ฑ ์žˆ๊ณ  ํšจ์œจ์ ์ธ ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

poll(2) ์‹œ์Šคํ…œ ํ˜ธ์ถœ์€ select()์™€ ๊ธฐ๋Šฅ์„ฑ์ด ๊ฐ™์œผ๋ฉฐ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋“ค์ด ๋“œ๋ฌธ๋“œ๋ฌธํ•œ ์ง‘ํ•ฉ์„ ๊ฐ์‹œํ•  ๋•Œ ์กฐ๊ธˆ ๋” ํšจ์œจ์ ์ด๋‹ค. ์š”์ฆ˜์€ ๋„๋ฆฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์—ญ์‚ฌ์ ์œผ๋กœ๋Š” select()๋ณด๋‹ค ์ด์‹์„ฑ์ด ๋‚ฎ์•˜๋‹ค.

๋ฆฌ๋ˆ…์Šค ์ „์šฉ์ธ epoll(7) API๋Š” ๋งŽ์€ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋“ค์„ ๊ฐ์‹œํ•  ๋•Œ select(2) ๋ฐ poll(2)๋ณด๋‹ค ํšจ์œจ์ ์ธ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

EXAMPLE

๋‹ค์Œ์€ select()์˜ ์œ ์šฉ์„ฑ์„ ๋” ์ œ๋Œ€๋กœ ๋ณด์—ฌ ์ฃผ๋Š” ์˜ˆ์‹œ์ด๋‹ค. ํ•œ TCP ํฌํŠธ์—์„œ ๋‹ค๋ฅธ ํฌํŠธ๋กœ ์ „๋‹ฌ์„ ํ•˜๋Š” TCP ํฌ์›Œ๋”ฉ ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

static int forward_port;

#undef max
#define max(x,y) ((x) > (y) ? (x) : (y))

static int
listen_socket(int listen_port)
{
    struct sockaddr_in addr;
    int lfd;
    int yes;

    lfd = socket(AF_INET, SOCK_STREAM, 0);
    if (lfd == -1) {
        perror("socket");
        return -1;
    }

    yes = 1;
    if (setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR,
            &yes, sizeof(yes)) == -1) {
        perror("setsockopt");
        close(lfd);
        return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_port = htons(listen_port);
    addr.sin_family = AF_INET;
    if (bind(lfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
        perror("bind");
        close(lfd);
        return -1;
    }

    printf("accepting connections on port %d\n", listen_port);
    listen(lfd, 10);
    return lfd;
}

static int
connect_socket(int connect_port, char *address)
{
    struct sockaddr_in addr;
    int cfd;

    cfd = socket(AF_INET, SOCK_STREAM, 0);
    if (cfd == -1) {
        perror("socket");
        return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_port = htons(connect_port);
    addr.sin_family = AF_INET;

    if (!inet_aton(address, (struct in_addr *) &addr.sin_addr.s_addr)) {
        fprintf(stderr, "inet_aton(): bad IP address format\n");
        close(cfd);
        return -1;
    }

    if (connect(cfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
        perror("connect()");
        shutdown(cfd, SHUT_RDWR);
        close(cfd);
        return -1;
    }
    return cfd;
}

#define SHUT_FD1 do {                                \
                     if (fd1 >= 0) {                 \
                         shutdown(fd1, SHUT_RDWR);   \
                         close(fd1);                 \
                         fd1 = -1;                   \
                     }                               \
                 } while (0)

#define SHUT_FD2 do {                                \
                     if (fd2 >= 0) {                 \
                         shutdown(fd2, SHUT_RDWR);   \
                         close(fd2);                 \
                         fd2 = -1;                   \
                     }                               \
                 } while (0)

#define BUF_SIZE 1024

int
main(int argc, char *argv[])
{
    int h;
    int fd1 = -1, fd2 = -1;
    char buf1[BUF_SIZE], buf2[BUF_SIZE];
    int buf1_avail = 0, buf1_written = 0;
    int buf2_avail = 0, buf2_written = 0;

    if (argc != 4) {
        fprintf(stderr, "Usage\n\tfwd <listen-port> "
                 "<forward-to-port> <forward-to-ip-address>\n");
        exit(EXIT_FAILURE);
    }

    signal(SIGPIPE, SIG_IGN);

    forward_port = atoi(argv[2]);

    h = listen_socket(atoi(argv[1]));
    if (h == -1)
        exit(EXIT_FAILURE);

    for (;;) {
        int ready, nfds = 0;
        ssize_t nbytes;
        fd_set readfds, writefds, exceptfds;

        FD_ZERO(&readfds);
        FD_ZERO(&writefds);
        FD_ZERO(&exceptfds);
        FD_SET(h, &readfds);
        nfds = max(nfds, h);

        if (fd1 > 0 && buf1_avail < BUF_SIZE)
            FD_SET(fd1, &readfds);
            /* ์ฐธ๊ณ : ์•„๋ž˜์—์„œ fd1์„ exceptfds์— ์ถ”๊ฐ€ํ•  ๋•Œ
               nfds๋ฅผ ๊ฐฑ์‹ ํ•จ. */
        if (fd2 > 0 && buf2_avail < BUF_SIZE)
            FD_SET(fd2, &readfds);

        if (fd1 > 0 && buf2_avail - buf2_written > 0)
            FD_SET(fd1, &writefds);
        if (fd2 > 0 && buf1_avail - buf1_written > 0)
            FD_SET(fd2, &writefds);

        if (fd1 > 0) {
            FD_SET(fd1, &exceptfds);
            nfds = max(nfds, fd1);
        }
        if (fd2 > 0) {
            FD_SET(fd2, &exceptfds);
            nfds = max(nfds, fd2);
        }

        ready = select(nfds + 1, &readfds, &writefds, &exceptfds, NULL);

        if (ready == -1 && errno == EINTR)
            continue;

        if (ready == -1) {
            perror("select()");
            exit(EXIT_FAILURE);
        }

        if (FD_ISSET(h, &readfds)) {
            socklen_t addrlen;
            struct sockaddr_in client_addr;
            int fd;

            addrlen = sizeof(client_addr);
            memset(&client_addr, 0, addrlen);
            fd = accept(h, (struct sockaddr *) &client_addr, &addrlen);
            if (fd == -1) {
                perror("accept()");
            } else {
                SHUT_FD1;
                SHUT_FD2;
                buf1_avail = buf1_written = 0;
                buf2_avail = buf2_written = 0;
                fd1 = fd;
                fd2 = connect_socket(forward_port, argv[3]);
                if (fd2 == -1)
                    SHUT_FD1;
                else
                    printf("connect from %s\n",
                            inet_ntoa(client_addr.sin_addr));

                /* ๋‹ซ์€ ์ด์ „ ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋“ค์˜ ์ด๋ฒคํŠธ ๋ฌด์‹œ. */
                continue;
            }
        }

        /* ์ฃผ์˜: OOB ๋ฐ์ดํ„ฐ๋ฅผ ์ผ๋ฐ˜ ๋ฐ์ดํ„ฐ ์ „์— ์ฝ์„ ๊ฒƒ */

        if (fd1 > 0 && FD_ISSET(fd1, &exceptfds)) {
            char c;

            nbytes = recv(fd1, &c, 1, MSG_OOB);
            if (nbytes < 1)
                SHUT_FD1;
            else
                send(fd2, &c, 1, MSG_OOB);
        }
        if (fd2 > 0 && FD_ISSET(fd2, &exceptfds)) {
            char c;

            nbytes = recv(fd2, &c, 1, MSG_OOB);
            if (nbytes < 1)
                SHUT_FD2;
            else
                send(fd1, &c, 1, MSG_OOB);
        }
        if (fd1 > 0 && FD_ISSET(fd1, &readfds)) {
            nbytes = read(fd1, buf1 + buf1_avail,
                      BUF_SIZE - buf1_avail);
            if (nbytes < 1)
                SHUT_FD1;
            else
                buf1_avail += nbytes;
        }
        if (fd2 > 0 && FD_ISSET(fd2, &readfds)) {
            nbytes = read(fd2, buf2 + buf2_avail,
                      BUF_SIZE - buf2_avail);
            if (nbytes < 1)
                SHUT_FD2;
            else
                buf2_avail += nbytes;
        }
        if (fd1 > 0 && FD_ISSET(fd1, &writefds) && buf2_avail > 0) {
            nbytes = write(fd1, buf2 + buf2_written,
                       buf2_avail - buf2_written);
            if (nbytes < 1)
                SHUT_FD1;
            else
                buf2_written += nbytes;
        }
        if (fd2 > 0 && FD_ISSET(fd2, &writefds) && buf1_avail > 0) {
            nbytes = write(fd2, buf1 + buf1_written,
                       buf1_avail - buf1_written);
            if (nbytes < 1)
                SHUT_FD2;
            else
                buf1_written += nbytes;
        }

        /* ๋ฐ์ดํ„ฐ ์“ฐ๊ธฐ๊ฐ€ ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ๋ฅผ ๋”ฐ๋ผ์žก์•˜๋Š”์ง€ ํ™•์ธ */

        if (buf1_written == buf1_avail)
            buf1_written = buf1_avail = 0;
        if (buf2_written == buf2_avail)
            buf2_written = buf2_avail = 0;

        /* ํ•œ์ชฝ์ด ์—ฐ๊ฒฐ์„ ๋‹ซ์•˜์Œ. ๋ฐ˜๋Œ€์ชฝ์—์„  ์™„์ „ํžˆ
           ๋น„์šธ ๋•Œ๊นŒ์ง€ ์“ฐ๊ธฐ๋ฅผ ๊ณ„์†. */

        if (fd1 < 0 && buf1_avail - buf1_written == 0)
            SHUT_FD2;
        if (fd2 < 0 && buf2_avail - buf2_written == 0)
            SHUT_FD1;
    }
    exit(EXIT_SUCCESS);
}

์œ„ ํ”„๋กœ๊ทธ๋žจ์€ telnet ์„œ๋ฒ„๊ฐ€ ์ „์†กํ•˜๋Š” OOB ์‹ ํ˜ธ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•ด ๋Œ€๋ถ€๋ถ„์˜ TCP ์—ฐ๊ฒฐ์„ ์ œ๋Œ€๋กœ ์ „๋‹ฌํ•œ๋‹ค. ์–‘๋ฐฉํ–ฅ ๋ชจ๋‘๋กœ ๋ฐ์ดํ„ฐ ํ๋ฆ„์ด ์žˆ๋Š” ๊นŒ๋‹ค๋กœ์šด ๋ฌธ์ œ๋ฅผ ์ž˜ ์ฒ˜๋ฆฌํ•œ๋‹ค. fork(2) ํ˜ธ์ถœ์„ ํ•ด์„œ ๊ฐ ์ŠคํŠธ๋ฆผ์— ์Šค๋ ˆ๋“œ๋ฅผ ํ•˜๋‚˜์”ฉ ์“ฐ๋Š” ๊ฒŒ ๋” ํšจ์œจ์ ์ด๋ผ ์ƒ๊ฐํ•  ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ œ ํ•ด ๋ณด๋ฉด ์ƒ๊ฐ๋ณด๋‹ค ๊นŒ๋‹ค๋กญ๋‹ค. ๋˜ fcntl(2)์„ ์จ์„œ ๋…ผ๋ธ”๋กœํ‚น I/O๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฑธ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ๋น„ํšจ์œจ์ ์ธ ํƒ€์ž„์•„์›ƒ ๋ฐฉ์‹์„ ์“ฐ๊ฒŒ ๋˜๋ฏ€๋กœ ์—ญ์‹œ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.

์ด ํ”„๋กœ๊ทธ๋žจ์—์„œ๋Š” ๋™์‹œ ์—ฐ๊ฒฐ ํ•œ ๊ฐœ๋งŒ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์ง€๋งŒ ๋ฒ„ํผ๋“ค์˜ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋‘๊ณ  ์—ฐ๊ฒฐ๋งˆ๋‹ค ํ•˜๋‚˜์”ฉ ์“ฐ๊ฒŒ ํ•˜๋ฉด ์†์‰ฝ๊ฒŒ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ํ˜„์žฌ๋Š” ์ƒˆ ์—ฐ๊ฒฐ์ด ๋“ค์–ด์˜ค๋ฉด ํ˜„์žฌ ์—ฐ๊ฒฐ์„ ๋ฒ„๋ฆฌ๊ฒŒ ๋œ๋‹ค.

SEE ALSO

accept(2), connect(2), ioctl(2), poll(2), read(2), recv(2), select(2), send(2), sigprocmask(2), write(2), sigaddset(3), sigdelset(3), sigemptyset(3), sigfillset(3), sigismember(3), epoll(7)


2019-03-06

โš ๏ธ **GitHub.com Fallback** โš ๏ธ