ååãåã åã®ç¶ãã
echoãµã¼ãã¼ãæ¸ãã¦ã¿ãã¨ãã®ã¡ã¢ ãã®1 ã½ã±ããAPIã¨TCP
è¤æ°ã¯ã©ã¤ã¢ã³ããåæã«æãããã«ä»¥ä¸ã®æ¹æ³ã§å¯¾å¿ãã¦ã¿ãã
- ããããã³ã°I/Oã®ã¾ã¾ãforkã使ã£ã¦è¤æ°ããã»ã¹ãç«ã¡ä¸ãã1ããã»ã¹1ã¯ã©ã¤ã¢ã³ãã§å¯¾å¿ãã
- éããããã³ã°I/Oã使ã£ã¦å¯¾å¿ããã1ããã»ã¹ã§è¤æ°ã¯ã©ã¤ã¢ã³ãã«å¯¾å¿ãã
- I/Oå¤éã使ã£ã¦å¯¾å¿ããã1ããã»ã¹ã§è¤æ°ã¯ã©ã¤ã¢ã³ãã«å¯¾å¿ãã
ä»åãUNIXãããã¯ã¼ã¯ããã°ã©ãã³ã°ã«ãä¸è©±ã«ãªãã¾ãã
forkã使ã£ãechoãµã¼ãã¼
åã
åä½ã£ãechoãµã¼ãã¼ãforkã使ã£ã¦ã1ã¯ã©ã¤ã¢ã³ãæ¯ã«1ããã»ã¹ãå²ãå½ã¦ãæ§ã«ããã accept
å¾ã« fork
ãã¦ã親ããã»ã¹ã§ã¯ã¯ã©ã¤ã¢ã³ãã¨ã®æ¥ç¶ç¨ã½ã±ããã§ãã connect_d
ã close
ãåããã»ã¹ã§ã¯Listenç¨ã½ã±ããã§ãã listener_d
ã close
ããã
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <sys/wait.h> void error(char *msg) { fprintf(stderr, "%s:%s\n", msg, strerror(errno)); exit(1); } int read_line(int socket, char *buf, int len) { char *s = buf; int slen = len; int c = read(socket, s, slen); while ((c > 0) && (s[c - 1] != '\n')) { s += c; slen = -c; c = read(socket, s, slen); } if (c < 0) { return c; } return len - slen; } int main(int argc, char *argv[]) { int listener_d = socket(PF_INET, SOCK_STREAM, 0); if (listener_d == -1) { error("socket err"); } struct sockaddr_in name; name.sin_family = AF_INET; name.sin_port = (in_port_t)htons(30000); name.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(listener_d, (struct sockaddr *) &name, sizeof(name)) == -1) { error("bind err"); } if (listen(listener_d, 1) == -1) { error("listen err"); } puts("wait..."); struct sockaddr_storage client_addr; unsigned int address_size = sizeof(client_addr); char buf[255]; while(1) { int connect_d = accept(listener_d, (struct sockaddr *)&client_addr, &address_size); if (connect_d == -1) { error("accept err"); } if (fork() == 0) { char *msg = "Hello World!\r\n"; write(connect_d, msg, strlen(msg)); read_line(connect_d, buf, sizeof(buf)); write(connect_d, buf, strlen(buf)); close(connect_d); exit(0); } close(connect_d); } return 0; }
forkã使ã£ã¦ããªãechoãµã¼ãã¼ã®å ´åã connect_d
ã close
ãããFINãéä¿¡ããã¯ã©ã¤ã¢ã³ãã¨ã®æ¥ç¶ãåããã fork
ã使ã£ãechoãµã¼ãã¼ã§ã¯è¦ªããã»ã¹ã connect_d
ã close
ããããã ã大ä¸å¤«ãªã®ã ããããUNIXãããã¯ã¼ã¯ããã°ã©ãã³ã°ã«ã¯ããæ¸ãã¦ããã
ãã¹ã¦ã®ãã¡ã¤ã«ãã½ã±ãããåç §ã«ã¦ã³ã¿ãæã£ã¦ãããã¨ãç解ãããã¨ãå¿ è¦ã§ãã
UNIXãããã¯ã¼ã¯ããã°ã©ãã³ã° P103
close
ããã¨åç
§ã«ã¦ã³ã¿ã1ã¤æ¸ãããããã0ã«ãªããªãã¨FINã¯éä¿¡ãããªãã親ããã»ã¹ã§ close
ãã¦ãåç
§ã«ã¦ã³ã¿ã2ãã1ã«æ¸ãã ããªã®ã§ãFINã¯éä¿¡ãããã¯ã©ã¤ã¢ã³ãã¨ã®æ¥ç¶ã¯åããªãã
åããã¦ã¿ã
echoãµã¼ãã¼ãèµ·åãã¦ç¢ºèªã
$ netstat -an | grep 30000 tcp 0 0 0.0.0.0:30000 0.0.0.0:* LISTEN $ lsof -i:30000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME fork_echo 11474 ubuntu 3u IPv4 246242056 0t0 TCP *:30000 (LISTEN) $ ll /proc/11474/fd total 0 dr-x------ 2 ubuntu ubuntu 0 Mar 12 07:09 ./ dr-xr-xr-x 9 ubuntu ubuntu 0 Mar 12 07:09 ../ lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:09 0 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:09 1 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:09 2 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:09 3 -> socket:[246242056]
ã¯ã©ã¤ã¢ã³ããã2ã¤æ¥ç¶ãã¦ã¿ãã
ã¯ã©ã¤ã¢ã³ã1
$ telnet 192.168.33.10 30000 Trying 192.168.33.10... Connected to 192.168.33.10. Escape character is '^]'. Hello World!
ã¯ã©ã¤ã¢ã³ã2
$ telnet 192.168.33.10 30000 Trying 192.168.33.10... Connected to 192.168.33.10. Escape character is '^]'. Hello World!
fork
ã使ã£ã¦ããªãechoãµã¼ãã¼ã®å ´åã¨ç°ãªãã両æ¹ã« Hello World!
ã¨ãµã¼ãã¼ããè¿äºãæ¥ã¦ãããã¨ãåããã
ãµã¼ãã¼ã§ç¢ºèªã
$ ps -xf PID TTY STAT TIME COMMAND 2767 ? S 0:00 sshd: ubuntu@pts/1 2768 pts/1 Ss 0:00 \_ -bash 11474 pts/1 S+ 0:00 \_ ./fork_echo_server 11479 pts/1 S+ 0:00 \_ ./fork_echo_server 11480 pts/1 S+ 0:00 \_ ./fork_echo_serve
親ããã»ã¹ã1ã¤ãåããã»ã¹ã2ã¤ã§ãã¦ããããã«ç¢ºèªã
$ lsof -i:30000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME fork_echo 11474 ubuntu 3u IPv4 246242056 0t0 TCP *:30000 (LISTEN) fork_echo 11479 ubuntu 4u IPv4 246242057 0t0 TCP 192.168.33.10:30000->192.168.33.1:59013 (ESTABLISHED) fork_echo 11480 ubuntu 4u IPv4 246242079 0t0 TCP 192.168.33.10:30000->192.168.33.1:59014 (ESTABLISHED) $ ll /proc/11474/fd total 0 dr-x------ 2 ubuntu ubuntu 0 Mar 12 07:09 ./ dr-xr-xr-x 9 ubuntu ubuntu 0 Mar 12 07:09 ../ lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:09 0 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:09 1 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:09 2 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:09 3 -> socket:[246242056] $ ll /proc/11479/fd total 0 dr-x------ 2 ubuntu ubuntu 0 Mar 12 07:10 ./ dr-xr-xr-x 9 ubuntu ubuntu 0 Mar 12 07:10 ../ lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:10 0 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:10 1 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:10 2 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:10 4 -> socket:[246242057] $ ll /proc/11480/fd total 0 dr-x------ 2 ubuntu ubuntu 0 Mar 12 07:10 ./ dr-xr-xr-x 9 ubuntu ubuntu 0 Mar 12 07:10 ../ lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:10 0 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:10 1 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:10 2 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:10 4 -> socket:[246242079]
3ã¤ã®ããã»ã¹ããããã1ã¤ãã¤ã½ã±ããã使ã£ã¦ãã親ããã»ã¹ã¯LISTENãã¦ãã½ã±ãããåããã»ã¹ã¯ã¯ã©ã¤ã¢ã³ãã¨æ¥ç¶ãã¦ãã½ã±ããã
ã¯ã©ã¤ã¢ã³ã2ã®æ¹ã§é©å½ãªæååãå ¥åããã¨ãæååãè¿ã£ã¦ãã¦ãµã¼ãã¼ããåæãããã
$ telnet 192.168.33.10 30000 Trying 192.168.33.10... Connected to 192.168.33.10. Escape character is '^]'. Hello World! hoge hoge Connection closed by foreign host.
ãµã¼ãã¼ã®ç¶æ
ã確èªãæ¥ç¶æ¸ã¿ã½ã±ããã1ã¤ã«ãªã£ã¦ããã¨ãããããåããã»ã¹ã® close
ãå®è¡ãããæã«ã½ã±ããã®åç
§ã«ã¦ã³ã¿ã0ã«ãªãããããµã¼ãã¼ã¯FINãéä¿¡ãã¦ãæçµçã«æ¥ç¶ãåããã
$ lsof -i:30000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME fork_echo 11474 ubuntu 3u IPv4 246242056 0t0 TCP *:30000 (LISTEN) fork_echo 11479 ubuntu 4u IPv4 246242057 0t0 TCP 192.168.33.10:30000->192.168.33.1:59013 (ESTABLISHED)
forkã使ã£ã¦ãè¤æ°ã¯ã©ã¤ã¢ã³ããåæã«åãæ±ããã¨ãã§ããã
psã§ãµã¼ãã¼å´ã®ããã»ã¹ã確èªãã¦ã¿ãã
$ ps -xf PID TTY STAT TIME COMMAND 2767 ? S 0:00 sshd: ubuntu@pts/1 2768 pts/1 Ss 0:00 \_ -bash 11474 pts/1 S+ 0:00 \_ ./fork_echo_server 11479 pts/1 S+ 0:00 \_ ./fork_echo_server 11480 pts/1 Z+ 0:00 \_ [fork_echo_serve] <defunct>
æ¥ç¶ãåããåãããããã¾ã³ãç¶æ ã§æ®ã£ã¦ãã¾ã£ã¦ããããã®åé¡ã«å¯¾å¿ããããã«SIGCHLDã·ã°ãã«ãå¦çãã¾ããããã¨ãã£ããã¨ãUNIXãããã¯ã¼ã¯ããã°ã©ãã³ã°ï¼5.8 Posixã®ã·ã°ãã«å¦çã5.9 SIGCHLDã·ã°ãã«ã®å¦çï¼ã«æ¸ãã¦ããã
ãã³ããããã³ã°I/Oã使ã£ãechoãµã¼ãã¼
ioctl
ã使ã£ã¦ listener_d
ï¼Listenç¨ã½ã±ããï¼ããã³ããããã³ã°ã«ããããã³ããããã³ã°ãªã½ã±ããã«å¯¾ã㦠accept
ããã¨ãã¯ã©ã¤ã¢ã³ãããã®æ¥ç¶ãæ¥ã¦ãªãå ´åããããã¯ããã«ããã« EWOULDBLOCK
ãè¿ãã
ã¯ã©ã¤ã¢ã³ãããã®æ¥ç¶ãæ¥ã¦ãå ´å㯠accept
ã§ããã¾ã§éãæ¥ç¶æ¸ã¿ã½ã±ãããè¿ãããã®æ¥ç¶æ¸ã¿ã½ã±ããã ioctl
ã使ã£ã¦ãã³ããããã³ã°ã«ããããã³ããããã³ã°ãªã½ã±ããã«å¯¾ã㦠read
ããã¨ããã¼ã¿ãå°éãã¦ããªãå ´åããããã¯ããã«ããã« EAGAIN
ãè¿ãã
ã³ã¼ãã¯ãããªæãã«ãªã£ãã
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <sys/ioctl.h> void error(char *msg) { fprintf(stderr, "%s:%s\n", msg, strerror(errno)); exit(1); } int read_line(int socket, char *buf, int len) { char *s = buf; int slen = len; int c = read(socket, s, slen); while ((c > 0) && (s[c - 1] != '\n')) { s += c; slen = -c; c = read(socket, s, slen); } if (c < 0) { return c; } return len - slen; } int main(int argc, char *argv[]) { int listener_d = socket(PF_INET, SOCK_STREAM, 0); if (listener_d == -1) { error("socket err"); } struct sockaddr_in name; name.sin_family = AF_INET; name.sin_port = (in_port_t)htons(30000); name.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(listener_d, (struct sockaddr *) &name, sizeof(name)) == -1) { error("bind err"); } if (listen(listener_d, 1) == -1) { error("listen err"); } puts("wait..."); struct sockaddr_storage client_addr; unsigned int address_size = sizeof(client_addr); // Listenã½ã±ããããã³ããããã³ã°ã«ãã int val = 1; if (ioctl(listener_d, FIONBIO, &val) == -1) { error("ioctl err"); } // æ¥ç¶æ¸ã¿ã½ã±ããã管çããããã®é å int fds[255]; // æ¥ç¶æ¸ã¿ã½ã±ããã®æ° int n = 0; char buf[255]; while(1) { int connect_d = accept(listener_d, (struct sockaddr *)&client_addr, &address_size); if (connect_d < 0) { // ã¯ã©ã¤ã¢ã³ãã®æ¥ç¶ããªãå ´å㯠EWOULDBLOCK if (errno != EWOULDBLOCK) { error("accept err"); } } else { // æ¥ç¶æ¸ã¿ã½ã±ããããã³ããããã³ã°ã«ãã if (ioctl(connect_d, FIONBIO, &val) == -1) { error("ioctl err"); } fds[n] = connect_d; n++; char *msg = "Hello World!\r\n"; write(connect_d, msg, strlen(msg)); } int i = 0; while (i < n) { // æ¥ç¶æ¸ã¿ã½ã±ãããé çªã«å¦ç int conn = fds[i]; if (read_line(conn, buf, sizeof(buf)) < 0) { // ãã¼ã¿ãå±ãã¦ãªãå ´å㯠EAGAIN if (errno != EAGAIN) { error("read err"); } i++; } else { // ãã¼ã¿ãå±ãã¦ãå ´åã¯echoãã¦close write(conn, buf, strlen(buf)); close(conn); n--; } } } return 0; }
ããã§ãUNIXãããã¯ã¼ã¯ããã°ã©ãã³ã°ã«æ¸ãã¦ãã£ã2ã¤ã®ã¹ããããæãåºãã
å ¥åæä½ã¯æ¬¡ã®2段éã§æ§æããã¦ããã - ãã¼ã¿ã®ç¨æãã§ããã¾ã§å¾ ã¡ã - ãã®ãã¼ã¿ãã«ã¼ãã«ããããã»ã¹ã«ã³ãã¼ããã
ã½ã±ããã«é¢ããå ¥åã§ã¯ãæåã®ã¹ãããã§ã¯æ®éã®ãããã¯ã¼ã¯ããã®ãã¼ã¿ã®å°çãå¾ ã¤ããã±ãããå°çããã¨ãã«ã¼ãã«å ã®ãããã¡ã«ã³ãã¼ãããã2ã¤ç®ã®ã¹ãããã§ã¯ããã®ãã¼ã¿ãã«ã¼ãã«ã®ãããã¡ããã¢ããªã±ã¼ã·ã§ã³ã®ãããã¡ã«ã³ãã¼ãããã¨ã«ãªãã
Unixãããã¯ã¼ãã³ã°ããã°ã©ãã³ã° P.140
accept
㨠read
ãã¹ããã1ã§ãããã¯ãã¦ãã¾ãã®ãåå ã§ãããããã³ã°I/Oã使ã£ãechoãµã¼ãã¼ã§ã¯è¤æ°ã¯ã©ã¤ã¢ã³ããæããªãã£ãããã³ããããã³ã°I/Oã§ã¯ã¹ããã1ã§ãã¼ã¿ãç¨æããã¦ããªãå ´åããããã¯ããã«ä½ããã®è¿ãå¤ãããã«è¿ãããã®ããããããã¯ããã«è¤æ°ã¯ã©ã¤ã¢ã³ããåæã«æããã¨ãã§ããã
åããã¦ã¿ã
ãã³ããããã³ã°I/Oã使ã£ãechoãµã¼ãã¼ãèµ·åãã¦ã確èªãã¦ã¿ãã
$ ps -xf PID TTY STAT TIME COMMAND 2767 ? S 0:00 sshd: ubuntu@pts/1 2768 pts/1 Ss 0:00 \_ -bash 11508 pts/1 R+ 0:02 \_ ./non_blocking_echo_server $ lsof -i:30000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME non_block 11508 ubuntu 3u IPv4 246242707 0t0 TCP *:30000 (LISTEN) $ ll /proc/11508/fd total 0 dr-x------ 2 ubuntu ubuntu 0 Mar 12 07:49 ./ dr-xr-xr-x 9 ubuntu ubuntu 0 Mar 12 07:49 ../ lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:50 0 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:50 1 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:49 2 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:50 3 -> socket:[246242707]
ã¯ã©ã¤ã¢ã³ããã2ã¤æ¥ç¶ãã¦ã¿ãã
ã¯ã©ã¤ã¢ã³ã1
$ telnet 192.168.33.10 30000 Trying 192.168.33.10... Connected to 192.168.33.10. Escape character is '^]'. Hello World!
ã¯ã©ã¤ã¢ã³ã2
$ telnet 192.168.33.10 30000 Trying 192.168.33.10... Connected to 192.168.33.10. Escape character is '^]'. Hello World!
forkã使ã£ãechoãµã¼ãã¼ã¨åæ§ã«ã両æ¹ã¨ã Hello World!
ã¨ãµã¼ãã¼ããè¿äºãæ¥ã¦ãã
ãµã¼ãã¼å´ã確èªã
$ ps -xf PID TTY STAT TIME COMMAND 2767 ? S 0:00 sshd: ubuntu@pts/1 2768 pts/1 Ss 0:00 \_ -bash 11508 pts/1 R+ 3:14 \_ ./non_blocking_echo_server
forkã使ã£ãechoãµã¼ãã¼ã¨ç°ãªããechoãµã¼ãã¼ã®ããã»ã¹ã¯1ã¤ãããªããããã«ç¢ºèªãã¦ã¿ãã
$ lsof -i:30000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME non_block 11508 ubuntu 3u IPv4 246242707 0t0 TCP *:30000 (LISTEN) non_block 11508 ubuntu 4u IPv4 303901660 0t0 TCP 192.168.33.10:30000->192.168.33.1:59337 (ESTABLISHED) non_block 11508 ubuntu 5u IPv4 305166582 0t0 TCP 192.168.33.10:30000->192.168.33.1:59338 (ESTABLISHED) $ ll /proc/11508/fd total 0 dr-x------ 2 ubuntu ubuntu 0 Mar 12 07:49 ./ dr-xr-xr-x 9 ubuntu ubuntu 0 Mar 12 07:49 ../ lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:50 0 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:50 1 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:49 2 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:50 3 -> socket:[246242707] lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:53 4 -> socket:[303901660] lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:53 5 -> socket:[305166582]
echoãµã¼ãã¼ã®ããã»ã¹ã3ã¤ã®ã½ã±ããï¼Listenç¨1ã¤ãæ¥ç¶æ¸ã¿2ã¤ï¼ã使ã£ã¦ãã
ã¯ã©ã¤ã¢ã³ã2ã®æ¹ã§é©å½ãªæååãå ¥åããã¨ãæååãè¿ã£ã¦ãã¦ãµã¼ãã¼ããåæãããã
$ telnet 192.168.33.10 30000 Trying 192.168.33.10... Connected to 192.168.33.10. Escape character is '^]'. Hello World! hoge hoge Connection closed by foreign host.
ãµã¼ãã¼ã®ç¶æ ã確èªãæ¥ç¶æ¸ã¿ã½ã±ããã1ã¤ã«ãªã£ã¦ããã¨ãåããã
$ lsof -i:30000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME non_block 11508 ubuntu 3u IPv4 246242707 0t0 TCP *:30000 (LISTEN) non_block 11508 ubuntu 4u IPv4 303901660 0t0 TCP 192.168.33.10:30000->192.168.33.1:59337 (ESTABLISHED) $ ll /proc/11508/fd total 0 dr-x------ 2 ubuntu ubuntu 0 Mar 12 07:49 ./ dr-xr-xr-x 9 ubuntu ubuntu 0 Mar 12 07:49 ../ lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:50 0 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:50 1 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:49 2 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:50 3 -> socket:[246242707] lrwx------ 1 ubuntu ubuntu 64 Mar 12 07:53 4 -> socket:[303901660]
è¤æ°ã¯ã©ã¤ã¢ã³ããåæã«æããã¨ãã§ãããã ãã©ãè¤æ°ã®ã½ã±ããã管çããã³ã¼ããå¾®å¦ã ãã strace
ããã¨åãããã¯ã©ã¤ã¢ã³ãããã®æ¥ç¶ããªãã¨ãã£ã¨ã«ã¼ãå¦çãåãã¦ãããããã¯ç¡é§ã次ã®I/Oå¤éã使ãã¨ãã£ã¨è¯ããªãã
I/Oã®å¤éåã使ã£ãechoãµã¼ãã¼
epoll
ã使ã£ã¦I/Oã®å¤éåã使ã£ãechoãµã¼ãã¼ãæ¸ãã
read
ã¯ã2ã¤ã®ã¹ããããè¡ãããI/Oã®å¤éåã§ã¯2ã¤ã®ã¹ãããã®ãã¡ã®1ã¤ç®ããã¼ã¿ã®ç¨æãã§ããã¾ã§å¾
ã¤ãã¨ããé¨åã ããåãåºãã¦è¡ãããã¼ã¿ãç¨æã§ããã¾ã§ãããã¯ãããã¼ã¿ãç¨æã§ãããã«ã¼ãã«ããããã»ã¹ã«æ»ã£ã¦ããããã®æã1ã¤ã®ãã£ã¹ã¯ãªãã¿ã ãã§ãªãè¤æ°ã®ãã£ã¹ã¯ãªãã¿ã«å¯¾ãã¦ãã¼ã¿ã®ç¨æãå¾
ã¤ãã¨ãã§ããã
I/Oã®å¤éåã®ããã®ã·ã¹ãã ã³ã¼ã«ã¯ããã¤ããããã epoll
ã使ãã epoll
ã§ã¯ã epoll_create
epoll_ctl
epoll_wait
ã¨ãã3ã¤ã®ã·ã¹ãã ã³ã¼ã«ãçµã¿åãããã
epoll_create
epoll_create
ã®å®ç¾©ãmanãèªã㨠size
ã®å¤ã¯æ£ã§ãªãã¨ãããªãããªãã§ãããããããç¾å¨ã¯ä½¿ããã¦ããªãã
#include <sys/epoll.h> int epoll_create(int size);
以ä¸ã®ãããªæãã§epollãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ããªã¼ãã³ããã
// epollãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ããªã¼ãã³ int epfd; if ((epfd = epoll_create(100)) < 0) { error("epoll_create err"); }
epoll_ctl
epoll_ctl
ã®å®ç¾©ãepollãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã¨ç£è¦å¯¾è±¡ã®ãã£ã¹ã¯ãªãã¿ã¨ã®é¢é£ãæä½ããã op
ã®å¤ã¨ã㦠EPOLL_CTL_ADD
ãæå®ããã¨ç£è¦å¯¾è±¡ã¨ãã¦è¿½å ã§ããã
#include <sys/epoll.h> int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epoll_ctlã使ã£ã¦ãechoãµã¼ãã¼ã® listener_d
ãepollã®ç£è¦å¯¾è±¡ã«ããã
// listener_dã½ã±ãããepollã®ç£è¦å¯¾è±¡ã¨ãã struct epoll_event ev; memset(&ev, 0, sizeof ev); ev.events = EPOLLIN; ev.data.fd = listener_d; if ((epoll_ctl(epfd, EPOLL_CTL_ADD, listener_d, &ev)) < 0) { error("epoll_ctl error"); }
epoll_wait
epoll ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã® I/O ã¤ãã³ããå¾
ã¤ã timeout
ã«-1ãæå®ããã¨æºåãã§ãããã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ãã§ããã¾ã§å¾
ã¡ç¶ãããè¿ãå¤ã¯æºåãã§ãã¦ãããã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã®æ°ã
第2å¼æ°ã® events
ã«ã¯å¼ã³åºãå¯è½ãªã¤ãã³ããæ ¼ç´ãããã
#include <sys/epoll.h> int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
listener_d
ãç£è¦å¯¾è±¡ã«ãã¦ããã epoll_wait
ãå¼ã¶ã timeout
ã« -1
ãæå®ãã¦ããã®ã§ã listener_d
ã®ã¯ã©ã¤ã¢ã³ãããã®æ¥ç¶ãæ¥ãã¾ã§ãããã¯ããã
struct epoll_event events[MAX_EVENTS]; while(1) { int fd_count = epoll_wait(epfd, events, MAX_EVENTS, -1); // æºåãã§ãããã£ã¹ã¯ãªãã¿ãé çªã«å¦ç int i; for (i = 0; i < fd_count; i++) { if (events[i].data.fd == listener_d ){ // ã¯ã©ã¤ã¢ã³ããæ¥ç¶ãã¦ããæã®å¦ç } else { // æºåãã§ãããã£ã¹ã¯ãªãã¿ãlisterner_dã§ã¯ãªãå ´åã®å¦ç } } } }
ã¯ã©ã¤ã¢ã³ããæ¥ç¶ãã¦ããæã®å¦çã¯ãåä¸ã¯ã©ã¤ã¢ã³ãã«ãã対å¿ã§ããªãechoãµã¼ãã¼ã®æã¨åæ§ã« accept
ãå¼ã³åºãã epoll_wait
ã§ã½ã±ããã®æºåãã§ããã¾ã§å¾
ã£ãã®ã§ããã® accept
ã§ã¯ãããã¯ããªãããã® accept
ã§åå¾ã§ããæ¥ç¶æ¸ã¿ã½ã±ããã®ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ãepollã®ç£è¦å¯¾è±¡ã¨ããã
struct epoll_event events[MAX_EVENTS]; while(1) { int fd_count = epoll_wait(epfd, events, MAX_EVENTS, -1); // æºåãã§ãããã£ã¹ã¯ãªãã¿ãé çªã«å¦ç int i; for (i = 0; i < fd_count; i++) { if (events[i].data.fd == listener_d ){ // ã¯ã©ã¤ã¢ã³ããæ¥ç¶ãã¦ããæã®å¦ç int connect_d = accept(listener_d, (struct sockaddr *)&client_addr, &address_size); if (connect_d == -1) { error("accept err"); } char *msg = "Hello World!\r\n"; write(connect_d, msg, strlen(msg)); // connect_dã½ã±ãããç£è¦å¯¾è±¡ã¨ãã memset(&ev, 0, sizeof ev); ev.events = EPOLLIN; ev.data.fd = connect_d; if ((epoll_ctl(epfd, EPOLL_CTL_ADD, connect_d, &ev)) < 0) { error("epoll_ctl error"); } } else { // æºåãã§ãããã£ã¹ã¯ãªãã¿ãlisterner_dã§ã¯ãªãå ´åã®å¦ç } } } }
æºåãã§ãããã£ã¹ã¯ãªãã¿ã listerner_d
ã§ã¯ãªãå ´åã¨ããã®ã¯ãã¤ã¾ãæºåãã§ãããã£ã¹ã¯ãªãã¿ãã¯ã©ã¤ã¢ã³ãã¨ã®æ¥ç¶ç¨ã½ã±ããã®ãã£ã¹ã¯ãªãã¿ã§ããå ´åã§ããããªã®ã§ãã¯ã©ã¤ã¢ã³ãããæååãå±ãã½ã±ããããåå¾ããæºåãã§ããã¨ãããã¨ã§ããããã®ç¶æ
㧠read
ãå¼ã³åºãã¦ããããã¯ãããæéã¯ãstep2ã®ãã¼ã¿ãã«ã¼ãã«ããããã»ã¹ã«ã³ãã¼ããé¨åã ããªã®ã§ãã»ã¨ãã©ãªãã
struct epoll_event events[MAX_EVENTS]; while(1) { int fd_count = epoll_wait(epfd, events, MAX_EVENTS, -1); // æºåãã§ãããã£ã¹ã¯ãªãã¿ãé çªã«å¦ç int i; for (i = 0; i < fd_count; i++) { if (events[i].data.fd == listener_d ){ // ã¯ã©ã¤ã¢ã³ããæ¥ç¶ãã¦ããæã®å¦ç int connect_d = accept(listener_d, (struct sockaddr *)&client_addr, &address_size); if (connect_d == -1) { error("accept err"); } char *msg = "Hello World!\r\n"; write(connect_d, msg, strlen(msg)); // connect_dã½ã±ãããç£è¦å¯¾è±¡ã¨ãã memset(&ev, 0, sizeof ev); ev.events = EPOLLIN; ev.data.fd = connect_d; if ((epoll_ctl(epfd, EPOLL_CTL_ADD, connect_d, &ev)) < 0) { error("epoll_ctl error"); } } else { // æºåãã§ãããã£ã¹ã¯ãªãã¿ãlisterner_dã§ã¯ãªãå ´åã®å¦ç int connect_d = events[i].data.fd; read_line(connect_d, buf, sizeof(buf)); write(connect_d, buf, strlen(buf)); close(connect_d); // closeããã½ã±ãããç£è¦å¯¾è±¡ããåé¤ epoll_ctl(epfd, EPOLL_CTL_DEL, connect_d, &ev); } } } }
epollã使ã£ãechoãµã¼ãã¼
ã³ã¼ãã¯ãããªæãã«ãªã£ãã
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <sys/epoll.h> const int MAX_EVENTS = 10; void error(char *msg) { fprintf(stderr, "%s:%s\n", msg, strerror(errno)); exit(1); } int read_line(int socket, char *buf, int len) { char *s = buf; int slen = len; int c = read(socket, s, slen); while ((c > 0) && (s[c - 1] != '\n')) { s += c; slen = -c; c = read(socket, s, slen); } if (c < 0) { return c; } return len - slen; } int main(int argc, char *argv[]) { int listener_d = socket(PF_INET, SOCK_STREAM, 0); if (listener_d == -1) { error("socket err"); } struct sockaddr_in name; name.sin_family = AF_INET; name.sin_port = (in_port_t)htons(30000); name.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(listener_d, (struct sockaddr *) &name, sizeof(name)) == -1) { error("bind err"); } if (listen(listener_d, 1) == -1) { error("listen err"); } puts("wait..."); struct sockaddr_storage client_addr; unsigned int address_size = sizeof(client_addr); char buf[255]; // epollãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ããªã¼ãã³ int epfd; if ((epfd = epoll_create(100)) < 0) { error("epoll_create err"); } // listener_dã½ã±ãããepollã®ç£è¦å¯¾è±¡ã¨ãã struct epoll_event ev; memset(&ev, 0, sizeof ev); ev.events = EPOLLIN; ev.data.fd = listener_d; if ((epoll_ctl(epfd, EPOLL_CTL_ADD, listener_d, &ev)) < 0) { error("epoll_ctl error"); } struct epoll_event events[MAX_EVENTS]; while(1) { int fd_count = epoll_wait(epfd, events, MAX_EVENTS, -1); // æºåãã§ãããã£ã¹ã¯ãªãã¿ãé çªã«å¦ç int i; for (i = 0; i < fd_count; i++) { if (events[i].data.fd == listener_d ){ // æºåãã§ãããã£ã¹ã¯ãªãã¿ãlistener_dã¨ãããã¨ã¯ // æ°ããã¯ã©ã¤ã¢ã³ããæ¥ç¶ãã¦ããã¨ããã㨠int connect_d = accept(listener_d, (struct sockaddr *)&client_addr, &address_size); if (connect_d == -1) { error("accept err"); } char *msg = "Hello World!\r\n"; write(connect_d, msg, strlen(msg)); // connect_dã½ã±ãããç£è¦å¯¾è±¡ã¨ãã memset(&ev, 0, sizeof ev); ev.events = EPOLLIN; ev.data.fd = connect_d; if ((epoll_ctl(epfd, EPOLL_CTL_ADD, connect_d, &ev)) < 0) { error("epoll_ctl error"); } } else { // connect_dã®æºåãã§ããã¨ãããã¨ã¯ // ã¯ã©ã¤ã¢ã³ãããã®ãã¼ã¿ãå±ããã¨ããã㨠int connect_d = events[i].data.fd; read_line(connect_d, buf, sizeof(buf)); write(connect_d, buf, strlen(buf)); close(connect_d); // closeããã½ã±ãããç£è¦å¯¾è±¡ããåé¤ epoll_ctl(epfd, EPOLL_CTL_DEL, connect_d, &ev); } } } return 0; }
åããã¦ã¿ã
I/Oã®å¤éåã使ã£ãechoãµã¼ãã¼ãèµ·åãã¦ã確èªãã¦ã¿ãã
$ lsof -i:30000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME epoll_ech 2836 ubuntu 3u IPv4 57737 0t0 TCP *:30000 (LISTEN) $ ll /proc/2836/fd total 0 dr-x------ 2 ubuntu ubuntu 0 Mar 5 12:50 ./ dr-xr-xr-x 9 ubuntu ubuntu 0 Mar 5 12:50 ../ lrwx------ 1 ubuntu ubuntu 64 Mar 5 12:50 0 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 5 12:50 1 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 5 12:50 2 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 5 12:50 3 -> socket:[57737] lrwx------ 1 ubuntu ubuntu 64 Mar 5 12:50 4 -> anon_inode:[eventpoll]
ã½ã±ããã ãã§ã¯ãªããepollç¨ã®ãã£ã¹ã¯ãªãã¿ã使ã£ã¦ãããã¨ãåããã
ã¯ã©ã¤ã¢ã³ããã2ã¤æ¥ç¶ãã¦ã¿ãã
ã¯ã©ã¤ã¢ã³ã1
$ telnet 192.168.33.10 30000 Trying 192.168.33.10... Connected to 192.168.33.10. Escape character is '^]'. Hello World!
ã¯ã©ã¤ã¢ã³ã2
$ telnet 192.168.33.10 30000 Trying 192.168.33.10... Connected to 192.168.33.10. Escape character is '^]'. Hello World!
forkã使ã£ãechoãµã¼ãã¼ã¨åæ§ã«ã両æ¹ã¨ã Hello World!
ã¨ãµã¼ãã¼ããè¿äºãæ¥ã¦ãã
ãµã¼ãã¼å´ã確èªã
$ lsof -i:30000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME epoll_ech 2836 ubuntu 3u IPv4 57737 0t0 TCP *:30000 (LISTEN) epoll_ech 2836 ubuntu 5u IPv4 60491 0t0 TCP 192.168.33.10:30000->192.168.33.1:49526 (ESTABLISHED) epoll_ech 2836 ubuntu 6u IPv4 60493 0t0 TCP 192.168.33.10:30000->192.168.33.1:49527 (ESTABLISHED) $ ll /proc/2836/fd total 0 dr-x------ 2 ubuntu ubuntu 0 Mar 5 12:50 ./ dr-xr-xr-x 9 ubuntu ubuntu 0 Mar 5 12:50 ../ lrwx------ 1 ubuntu ubuntu 64 Mar 5 12:50 0 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 5 12:50 1 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 5 12:50 2 -> /dev/pts/1 lrwx------ 1 ubuntu ubuntu 64 Mar 5 12:50 3 -> socket:[57737] lrwx------ 1 ubuntu ubuntu 64 Mar 5 12:50 4 -> anon_inode:[eventpoll] lrwx------ 1 ubuntu ubuntu 64 Mar 5 12:53 5 -> socket:[60491] lrwx------ 1 ubuntu ubuntu 64 Mar 5 12:53 6 -> socket:[60493] $ sudo strace -s 1024 -p 2836 strace: Process 2836 attached epoll_wait(4, $ ps x | grep epoll_echo_server 2836 pts/1 S+ 0:00 ./epoll_echo_server
2ã¤ã®æ¥ç¶æ¸ã¿ã½ã±ãããä½æããã¦ãããã¾ãã strace
ã®çµæãã read
ã§ã¯ãªã epoll_wait
ã§ããããã³ã°ãã¦ãããã¨ãåããã ps
ã®çµæããecho_serverã®ããã»ã¹ã¯1ã¤ã ãã§ãããã¨ãåããã
epollã使ã£ã¦I/Oå¤éãè¡ããã¨ã§ã1ã¤ã®ããã»ã¹ã§ãè¤æ°ã¯ã©ã¤ã¢ã³ããæããã¨ãã§ããã
ãããã¯ãã¦ã¯ãããªã
I/Oå¤éã«ãã£ã¦ã½ã±ããã®ãããã¯ããªããã1ããã»ã¹ã§è¤æ°ã¯ã©ã¤ã¢ã³ããæããããã«ãªã£ããããããã¯ãã¦ãã¾ãå¯è½æ§ã¯ã¾ã æ®ã£ã¦ãããããã¯åé¡ã§ã1ããã»ã¹ã§åãã¦ããã®ã§ãããã¯ãçºçãã¦ãã¾ãã¨echoãµã¼ãã¼å ¨ä½ã®å¦çãæ¢ã¾ã£ã¦ãã¾ãã
ã¾ããepollã§ãã£ã¹ã¯ãªãã¿ã®æºåãã§ããã½ã±ããããèªã¿è¾¼ãããã«ããããæºåãã§ãã ãããããªã ã ãã§ãã£ã¦å®æ½ã«èªã¿è¾¼ãã¨ããããã³ã°ãã¦ãã¾ãå ´åããããããããã®ããããã¨ãepollã使ã£ãã¨ãã¦ãã½ã±ããããã³ããããã³ã°I/Oã«ãã¦ãããªã©ã®å¯¾å¿ãå¿ è¦ã§ããã
ä»ã®I/Oã§ããããã¯ãã¦ã¯ãããªããä¾ãã°ããã¡ã¤ã«èªã¿è¾¼ã¿ãä»ã®ãµã¼ãã¼ã¨ã®éä¿¡ãªã©ããããã®I/Oã§ãããã³ããããã³ã°I/OãéåæI/Oï¼POSIX AIO ã¤ã³ã¿ã¼ãã§ã¼ã¹ï¼ãã¾ãã¯ã¹ã¬ããã使ãI/Oå¦çãå¥ã¹ã¬ããã«ä»»ãããããªéåæå¦çãè¡ãå¿ è¦ãããã
ã¾ããã½ã±ããããã®èªã¿è¾¼ã¿ã®ãããã¯ã¯ãªãããã¨ãã§ããããæ¸ãè¾¼ã¿ã§ãããã¯ãã¦ãã¾ãå ´åããããã¢ããªã±ã¼ã·ã§ã³ããã«ã¼ãã«å ã®ãããã¡ã«æ¸ãè¾¼ããããã®æãããã¡ãä¸æ¯ã ã¨ãããã¯ãã¦ãã¾ããããã§ããã¯ããããã¯ããªãããã«ãã³ããããã³ã°I/OãI/Oå¤éãéåæI/Oãã¹ã¬ãããªã©ã§å·¥å¤«ããå¿ è¦ãããã
ã¬ãã«ããªã¬ã¼ã¨ã¨ãã¸ããªã¬ã¼
epollã®éç¥æ¹æ³ã¨ãã¦ã¬ãã«ããªã¬ã¼ã¨ã¨ãã¸ããªã¬ã¼ã¨ããããããã©ã«ãã¯ã¬ãã«ããªã¬ã¼ãã¨ãã¸ããªã¬ã¼ã®æ¹ãè¯ãå ´é¢ãè¯ãåãããªãã£ããã©ãã©ãããæ¸ãè¾¼ã¿ã®ã¨ãã«ä¾¿å©ã£ã½ãã
epoll, エッジトリガー, EPOLLRDHUP - 誰かの役に立てばいいブログ
libev
epollã¯Linuxã§ä½¿ããããBSDã§ã¯ä½¿ããªããããã代ããã«kqueueã¨ããã·ã¹ãã ã³ã¼ã«ãããããã®ãããªãã©ãããã©ã¼ã ä¾åãé è½åããã©ã¤ãã©ãªã¨ãã¦libevããããlibevã使ã£ãechoãµã¼ãã¼ãæ¸ãã¦ã¿ããlibevã§ã¯epollã®å ´åã¨ç°ãªããã«ã¼ãå¦çãèªåã§æ¸ãå¿ è¦ããªããã³ã¼ã«ããã¯ãç»é²ããã³ã¼ãã«ãªãã
libevãã¤ã³ã¹ãã¼ã«ã
$ sudo apt-get install libev-dev
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <ev.h> void error(char *msg) { fprintf(stderr, "%s:%s\n", msg, strerror(errno)); exit(1); } int read_line(int socket, char *buf, int len) { char *s = buf; int slen = len; int c = read(socket, s, slen); while ((c > 0) && (s[c - 1] != '\n')) { s += c; slen = -c; c = read(socket, s, slen); } if (c < 0) { return c; } return len - slen; } void connect_callback(EV_P_ ev_io *watcher, int revents) { char buf[255]; read_line(watcher->fd, buf, sizeof(buf)); write(watcher->fd, buf, strlen(buf)); ev_io_stop(EV_A_ watcher); close(watcher->fd); free(watcher); } void listener_callback(EV_P_ ev_io *watcher, int revents) { struct sockaddr_storage client_addr; unsigned int address_size = sizeof(client_addr); int connect_d = accept(watcher->fd, (struct sockaddr *)&client_addr, &address_size); if (connect_d == -1) { error("accept err"); } char *msg = "Hello World!\r\n"; write(connect_d, msg, strlen(msg)); struct ev_loop *l; ev_io *connect_watcher; connect_watcher = malloc(sizeof(client_addr)); l = watcher->data; // connect_dãç£è¦ ev_io_init(connect_watcher, connect_callback, connect_d, EV_READ); ev_io_start(l, connect_watcher); } int main(int argc, char *argv[]) { int listener_d = socket(PF_INET, SOCK_STREAM, 0); if (listener_d == -1) { error("socket err"); } struct sockaddr_in name; name.sin_family = AF_INET; name.sin_port = (in_port_t)htons(30000); name.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(listener_d, (struct sockaddr *) &name, sizeof(name)) == -1) { error("bind err"); } if (listen(listener_d, 1) == -1) { error("listen err"); } puts("wait..."); // ã¤ãã³ãã«ã¼ãã®åæå struct ev_loop *loop; ev_io watcher; loop = ev_default_loop(0); watcher.data = loop; // listener_dãç£è¦ ev_io_init(&watcher, listener_callback, listener_d, EV_READ); ev_io_start(loop, &watcher); // ã¤ãã³ãã«ã¼ãéå§ ev_loop(loop, 0); close(listener_d); return 0; }
$ gcc libev_echo_server.c -l ev -o libev_echo_server
åããã¦
$ ./libev_echo_server
確èªã epoll_wait
ã§ãããã¯ãã¦ããã¨ããããã
$ lsof -i:30000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME libev_ech 13301 ubuntu 3u IPv4 566626035 0t0 TCP *:30000 (LISTEN) $ ll /proc/13301/fd total 0 dr-x------ 2 ubuntu ubuntu 0 Mar 18 13:03 ./ dr-xr-xr-x 9 ubuntu ubuntu 0 Mar 18 13:03 ../ lrwx------ 1 ubuntu ubuntu 64 Mar 18 13:03 0 -> /dev/pts/0 lrwx------ 1 ubuntu ubuntu 64 Mar 18 13:03 1 -> /dev/pts/0 lrwx------ 1 ubuntu ubuntu 64 Mar 18 13:03 2 -> /dev/pts/0 lrwx------ 1 ubuntu ubuntu 64 Mar 18 13:03 3 -> socket:[566626035] lrwx------ 1 ubuntu ubuntu 64 Mar 18 13:03 4 -> anon_inode:[eventpoll] lrwx------ 1 ubuntu ubuntu 64 Mar 18 13:03 5 -> anon_inode:[eventfd] $ sudo strace -s 1024 -p 13301 strace: Process 13301 attached epoll_wait(4,
ããã¾ã
echoãµã¼ãã¼ãæ¸ããªããããããããªI/Oã¢ãã«ã試ãã¦ã¿ããNode.jsã¯å ã libevã¨libeioï¼ã¹ã¬ããã使ã£ãéåæå¦çã§I/Oãè¡ãããã®ã©ã¤ãã©ãªï¼ã使ã£ã¦ããããç¾å¨ã¯ä¸¡æ¹ã¨ãlibuvã使ããã¦ãããããã
UNIXãããã¯ã¼ã¯ããã°ã©ãã³ã°ãèªã¿ãªããã³ã¼ããæ¸ãã¨ããããã¯ã¼ã¯ã®è©±ã¨ã³ã¼ããã¤ãªãã£ã¦ããæãããã¦æ¥½ããã£ãã
ã³ã¼ãã¯ãã¡ãã