select_tut(2) - wariua/manpages-ko GitHub Wiki
select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - ๋๊ธฐ์ I/O ๋ค์คํ
/* 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
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()
์ฌ์ฉ ์ ์ฃผ์ํด์ผ ํ ํต์ฌ ์ฌํญ๋ค์ ์ฌ๊ธฐ ๋์ดํ๋ค.
-
๊ฐ๊ธ์
select()
๋ฅผ ํ์์์ ์์ด ์ฐ๋ ๊ฒ ์ข๋ค. ๊ฐ์ฉ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด ํ๋ก๊ทธ๋จ์์ ํ ์ผ์ด ์์ด์ผ ํ๋ค. ํ์์์์ ์์กดํ๋ ์ฝ๋๋ ํญ์ ์ด์ ๊ฐ๋ฅํ์ง๋ ์์ผ๋ฉฐ ๋๋ฒ๊ทธ ํ๊ธฐ ์ด๋ ต๋ค. -
ํจ์จ์ฑ์ ์ํด
nfds
์ ๊ฐ์ ์์ ์ค๋ช ํ ๊ฒ์ฒ๋ผ ์ฌ๋ฐ๋ก ๊ณ์ฐํด์ผ ํ๋ค. -
select()
ํธ์ถ ํ์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํด์ ์ ์ ํ ๋์ํ ๊ฒ ์๋๋ผ๋ฉด ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ฅผ ์๋ฌด ์งํฉ์๋ ์ถ๊ฐํ์ง ๋ง๋ผ. ๋ค์ ๊ท์น ์ฐธ๊ณ . -
select()
๋ฐํ ํ์ ๋ชจ๋ ์งํฉ์ ๋ชจ๋ ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ค์ ํ์ธํ๋ ๊ฒ ์ข๋ค. -
read(2)
, recv(2),write(2)
, send(2) ํจ์๊ฐ ๊ผญ ์์ฒญ ๋ฐ์ดํฐ ๋ชจ๋๋ฅผ ์ฝ๋/์ฐ๋ ๊ฒ์ ์๋๋ค. ์ ์ฒด๋ฅผ ์ฝ๋๋ค๋ฉด/์ด๋ค๋ฉด ๊ทธ๊ฑด ํธ๋ํฝ ๋ถํ๊ฐ ์๊ณ ์คํธ๋ฆผ์ด ๋น ๋ฅด๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋ฐ๋ฐ ํญ์ ๊ทธ๋ ์ง๋ ์๋ค. ํจ์์์ ํ ๋ฐ์ดํธ๋ง ๊ฒจ์ฐ ๋ณด๋ด๊ฑฐ๋ ๋ฐ๋ ๊ฒฝ์ฐ์ ๋์ฒํด์ผ ํ๋ค. -
์ฒ๋ฆฌํ ๋ฐ์ดํฐ๊ฐ ์ ๋ง ์กฐ๊ธ๋ง ์๋ ๊ฒฝ์ฐ๊ฐ ์๋๋ฉด ์ ๋ ํ๋ฒ์ ํ ๋ฐ์ดํธ์ฉ ์ฝ์ง/์ฐ์ง ๋ง๋ผ. ๋ฒํผ๋ฅผ ์ต๋ํ ์ฑ์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ง/์ฐ์ง ์์ผ๋ฉด ๋งค์ฐ ๋นํจ์จ์ ์ผ๋ก ๋๋ค. ์๋ ์์ ๋ฒํผ๋ค์ 1024๋ฐ์ดํธ์ง๋ง ์์ฝ๊ฒ ํฌ๊ธฐ๋ฅผ ํค์ธ ์ ์๋ค.
-
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
์ด ๋์ค์ง ์์ ๊ฒ์ด๋ค. -
์ ๋๋ก ๋ฒํผ ๊ธธ์ด๋ฅผ 0์ผ๋ก ํด์
read(2)
, recv(2),write(2)
, send(2)๋ฅผ ํธ์ถํ์ง ๋ง๋ผ. -
ํจ์
read(2)
, recv(2),write(2)
, send(2)๊ฐ 7๋ฒ์ ๋์ดํ ๊ฒ ์ธ์ ์ค๋ฅ๋ก ์คํจํ๊ฑฐ๋ ์ ๋ ฅ ํจ์๋ค์ด ํ์ผ ๋์ ๋ํ๋ด๋ 0์ ๋ฐํํ๋ ๊ฒฝ์ฐ์๋ ๊ทธ ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ฅผselect()
๋ก ๋ค์ ์ ๋ฌํ์ง ์์์ผ ํ๋ค. ์ ์์์๋ ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ฅผ ์ฆ์ ๋ซ๊ณ ์ -1๋ก ์ค์ ํด์ ์งํฉ์ ํฌํจ๋๋ ๊ฑธ ๋ฐฉ์งํ๋ค. -
select()
๋ฅผ ํธ์ถํ ๋๋ง๋ค ํ์์์ ๊ฐ์ ์ค์ ํด์ผ ํ๋ค. ์ผ๋ถ ์ด์ ์ฒด์ ์์ ๊ทธ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ณ๊ฒฝํ๊ธฐ ๋๋ฌธ์ด๋ค. ํ์ง๋งpselect()
์์๋ ํ์์์ ๊ตฌ์กฐ์ฒด๋ฅผ ๋ณ๊ฒฝํ์ง ์๋๋ค. -
select()
์์ ํ์ผ ๋์คํฌ๋ฆฝํฐ ์งํฉ๋ค์ ๋ณ๊ฒฝํ๋ฏ๋ก ๋ฃจํ ์์์ ํธ์ถ์ ํ๋ ๊ฒฝ์ฐ๋ผ๋ฉด ํธ์ถ ์ ์ ๋งค๋ฒ ์งํฉ๋ค์ ๋ค์ ์ค์ ํด์ผ ํ๋ค.
usleep(3) ํจ์๊ฐ ์๋ ์์คํ
์์๋ ๋ค์์ฒ๋ผ ํ์ผ ๋์คํฌ๋ฆฝํฐ ์์ด ์ ํด์ง ํ์์์์ผ๋ก select()
๋ฅผ ํธ์ถํ ์ ์๋ค.
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 200000; /* 0.2 ์ด */
select(0, NULL, NULL, NULL, &tv);
๋ค๋ง ์ ๋์ค ์์คํ ๋ค์์๋ง ๋์์ด ๋ณด์ฅ๋๋ค.
์ฑ๊ณต ์ select()
๋ ํ์ผ ๋์คํฌ๋ฆฝํฐ ์งํฉ๋ค์ ์์ง ์๋ ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ค์ ์ด๊ฐ์๋ฅผ ๋ฐํํ๋ค.
select()
๊ฐ ํ์์์ ๋๋ฉด ๋ฐํ ๊ฐ์ด 0์ด ๋๋ค. ํ์ผ ๋์คํฌ๋ฆฝํฐ ์งํฉ์ด ๋ชจ๋ ๋น์ด ์์ ๊ฒ์ด๋ค. (ํ์ง๋ง ์ด๋ค ์์คํ
์์๋ ๊ทธ๋ ์ง ์์ ์๋ ์๋ค.)
๋ฐํ ๊ฐ -1์ ์ค๋ฅ๋ฅผ ๋ํ๋ด๋ฉฐ errno
๊ฐ ์ ์ ํ ์ค์ ๋๋ค. ์ค๋ฅ ๊ฒฝ์ฐ์ ๋ฐํ๋ ์งํฉ๋ค์ ๋ด์ฉ๊ณผ struct timeout
์ ๋ด์ฉ์ ๊ท์ ๋ผ ์์ง ์์ผ๋ฏ๋ก ์ฌ์ฉํ์ง ๋ง์์ผ ํ๋ค. ๋ค๋ง pselect()
์์๋ ์ ๋ ntimeout
์ ๋ณ๊ฒฝํ์ง ์๋๋ค.
์ผ๋ฐ์ ์ผ๋ก ๋งํด์ ์์ผ์ ์ง์ํ๋ ์ด์ ์ฒด์ ๋ค์ ๋ชจ๋ select()
๋ ์ง์ํ๋ค. select()
๋ฅผ ์ฐ๋ฉด ์ด๋ณด ํ๋ก๊ทธ๋๋จธ๊ฐ ์ค๋ ๋, ํฌํฌ, IPC, ์๊ทธ๋, ๋ฉ๋ชจ๋ฆฌ ๊ณต์ ๋ฑ์ ์ด์ฉํด ๋ณต์กํ๊ฒ ํด๊ฒฐํ๋ ค ํ๋ ์ฌ๋ฌ ๋ฌธ์ ๋ค์ ์ด์์ฑ ์๊ณ ํจ์จ์ ์ธ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ ์ ์๋ค.
poll(2) ์์คํ
ํธ์ถ์ select()
์ ๊ธฐ๋ฅ์ฑ์ด ๊ฐ์ผ๋ฉฐ ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ค์ด ๋๋ฌธ๋๋ฌธํ ์งํฉ์ ๊ฐ์ํ ๋ ์กฐ๊ธ ๋ ํจ์จ์ ์ด๋ค. ์์ฆ์ ๋๋ฆฌ ์ฌ์ฉ ๊ฐ๋ฅํ์ง๋ง ์ญ์ฌ์ ์ผ๋ก๋ select()
๋ณด๋ค ์ด์์ฑ์ด ๋ฎ์๋ค.
๋ฆฌ๋ ์ค ์ ์ฉ์ธ epoll(7) API๋ ๋ง์ ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ค์ ๊ฐ์ํ ๋ select(2) ๋ฐ poll(2)๋ณด๋ค ํจ์จ์ ์ธ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ค.
๋ค์์ 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๋ฅผ ์ค์ ํ๋ ๊ฑธ ์๊ฐํ ์ ์๋ค. ํ์ง๋ง ๋นํจ์จ์ ์ธ ํ์์์ ๋ฐฉ์์ ์ฐ๊ฒ ๋๋ฏ๋ก ์ญ์ ๋ฌธ์ ๊ฐ ์๋ค.
์ด ํ๋ก๊ทธ๋จ์์๋ ๋์ ์ฐ๊ฒฐ ํ ๊ฐ๋ง ์ฒ๋ฆฌํ๊ณ ์์ง๋ง ๋ฒํผ๋ค์ ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ฅผ ๋๊ณ ์ฐ๊ฒฐ๋ง๋ค ํ๋์ฉ ์ฐ๊ฒ ํ๋ฉด ์์ฝ๊ฒ ํ์ฅํ ์ ์๋ค. ํ์ฌ๋ ์ ์ฐ๊ฒฐ์ด ๋ค์ด์ค๋ฉด ํ์ฌ ์ฐ๊ฒฐ์ ๋ฒ๋ฆฌ๊ฒ ๋๋ค.
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