select_tut

SELECT_TUT(2)              Linux Programmer's Manual             SELECT_TUT(2)



åå
       select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - åæ I/O ã®å¤éå

æ¸å¼
       /* POSIX.1-2001 ã«å¾ãå ´å */
       #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 || _XOPEN_SOURCE >= 600

説æ
       select()  (ã pselect())  ã使ãã¨ãå¹ççã«è¤æ°ã®ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ãç£è¦ãã
       ãã®ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã®ããããã ãready (æºåãã§ãã)ãç¶æãã¤ã¾ã I/O (å¥åºå)
       ãå¯è½ã«ãªã£ã¦ããããã ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã®ããããã ãä¾å¤ç¶æ (exceptional
       condition)ããçºçããããã調ã¹ããã¨ãã§ããã

       ãã®é¢æ°ã®ä¸»è¦ãªå¼ãæ°ã¯ã3種é¡ã®ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã®ãéåã 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
              ãã®éåã«å«ã¾ããããããã®ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã§ã ãä¾å¤ç¶æ (exceptional
              condition)ããçºçãããã©ãããç£è¦ããã
              å®éã®åä½ã§ã¯ãæ®éã«èµ·ããå¾ãä¾å¤ç¶æã¯ä¸ã¤ã ãã§ããã ãã㯠TCP
              ã½ã±ãã㧠帯åå¤ (out-of-band; OOB) ãã¼ã¿ã èª‐
              ã¿è¾¼ã¿å¯è½ãªå ´åã§ããã OOB ãã¼ã¿ã®è©³ç´°ã«ã¤ãã¦ã¯ã recv(2),
              send(2), tcp(7)  ãåç§ã®ãã¨ã (ãã以å¤ã§ã¯ãã¾ããªãã¨ã ãã
              ãã±ããã¢ã¼ãã®æ¬ä¼¼ç«¯æ« (pseudoterminals) 㧠select()
              ãä¾å¤ç¶æã示ããã¨ãããã)  select()  ãè¿ãæã«ãexceptfds ã®ãã¡ã
              ä¾å¤ç¶æãçºçãããã£ã¹ã¯ãªãã¿ä»¥å¤ã¯éåããåé¤ãããã

       nfds   å¨ã¦ã®éåã«å«ã¾ãããã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã®ãã¡ã å¤ãæ大ã®ãã®ã« 1
              ã足ããæ´æ°ã§ããã ããªãã¡ããã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ãåéåã«å ããä½æ¥ã®éä¸ã§ã
              å¨ã¦ã®ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ãè¦ã¦æ大å¤ãæ±ãã ããã« 1 ãå ã㦠nfds
              ã¨ãã¦æ¸¡ããªãã¨ãããªããã¨ãããã¨ã ã

       utimeout
              (ä½ãèµ·ãããªãã£ãå ´åã«)  select()  ãæ»ãåã«å¾ã¤æ大æéã§ããã ãã®å¤ã«
              NULL ã渡ãã¨ã select() ã¯ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã®ããããã ready
              (æºåãã§ãã) ç¶æã« ãªãã¾ã§å¾ã¡ç¶ãã¦ãã£ã¨åæ¢ããã utimeout 㯠0
              ç§ã«ãããã¨ãã§ãã ãã®å ´å select()
              ã¯ç´ã¡ã«è¿ããå¼ã³åºãæç¹ã®ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã®ç¶æã«
              é¢ããæå ±ãè¿ãããã æ§é ä½ struct timeval ã¯æ¬¡ã®ããã«å®ç¾©ããã¦ãã:

                  struct timeval {
                      time_t tv_sec;    /* seconds */
                      long tv_usec;     /* microseconds */
                  };

       ntimeout
              pselect()  ã®ãã®å¼ãæ°ã¯ utimeout ã¨åãæå³ãæã¤ãã struct timespec
              ã¯æ¬¡ã«ç¤ºãããã«ããç§ã®ç²¾åº¦ãæã¤ã

                  struct timespec {
                      long tv_sec;    /* seconds */
                      long tv_nsec;   /* nanoseconds */
                  };

       sigmask
              ãã®å¼ãæ°ã¯ãå¼ã³åºãå´ã pselect()  åé¨ã§åæ‐
              ¢ãã¦ããéã«ãã«ã¼ãã«ãéç¥ã許å¯ãã¹ãã·ã°ãã«éå
              (ããªãã¡ãå¼ã³åºããã¹ã¬ããã®ã·ã°ãã«ãã¹ã¯ããåé¤ãã¹ãã·ã°ãã«éå)  ãä¿æãã
              (sigaddset(3)  㨠sigprocmask(2)  ãåç§)ã ãã®å¼ãæ°ã¯ NULL
              ã«ãããã¨ãã§ãããã®å ´åã¯ãã®é¢æ°ã¸
              å¥ãã¨ãã»åºãã¨ãã«ã·ã°ãã«ãã¹ã¯ãå¤æ´ããªãã ãã®å ´åã pselect()  ã¯
              select()  ã¨å¨ãåãåä½ã¨ãªãã

   ã·ã°ãã«ã¨ãã¼ã¿ã¤ãã³ããçµã¿åããã
       ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã I/O å¯è½ãªç¶æã«ãªãã®ã¨åæã« ã·ã°ãã«ãå¾ã¡ããå ´åã«ã¯ã
       pselect()  ã便å©ã§ããã ã·ã°ãã«ãåä¿¡ããããã°ã©ã ã¯ãé常ã¯ã
       ã·ã°ãã«ãã³ãã©ãã°ãã¼ãã«ãªãã©ã°ãç«ã¦ãããã ãã«ä½¿ãã ãã®ã°ãã¼ãã«ãªãã©ã°ã¯ã
       ãã®ã¤ãã³ããããã°ã©ã ã®ã¡ã¤ã³ã«ã¼ã㧠å¦çããªããã°ãªããªããã¨ã示ãã
       ã·ã°ãã«ãåãã㨠select()  (ã pselect())  㯠errno ã« EINTR
       ãã»ãããã¦æ»ããã¨ã«ãªãã ã·ã°ãã«ããã‐
       ã°ã©ã ã®ã¡ã¤ã³ã«ã¼ãã§å¦çãããããã«ã¯ãã®åä½ãä¸å¯æ¬ ã§ã ããããªã㨠select()
       ã¯æ°¸é ã«åæ¢ãç¶ãããã¨ã«ãªãã ãã¦ãã¡ã¤ã³ã«ã¼ãã®ã©ããã«ãã®ã°ã‐
       ã¼ãã«ãã©ã°ããã§ãã¯ãã æ¡ä»¶æãããã¨ããããããã§å°ãèãã¦ã¿ãªãã¨ãããªãã
       ãã·ã°ãã«ãæ¡ä»¶æã®å¾ãããã select()  ã³ã¼ã«ã®åã«å°çããã ã©ããªãã®ãï¼ã ç‐
       ãã¯ããã® select() ã¯ããã¨ã解決å¾ã¡ã®ã¤ãã³ãããã£ãã¨ãã¦ãã æ°¸é ã«åæ‐
       ¢ãããã§ããã ãã®ç«¶åç¶æ㯠pselect()  ã³ã¼ã«ã«ãã£ã¦è§£æ±ºã§ããã
       ãã®ã³ã¼ã«ã使ãã¨ã pselect()  ã§åä¿¡ãããã·ã°ãã«ã®éåã ããã·ã°ãã«ãã¹ã¯ã«è¨‐
       å®ãããã¨ãã§ããã ä¾ãã°ãåé¡ã¨ãªã£ã¦ããã¤ãã³ããåããã»ã¹ã®çµäºã®å ´åãèãããã
       ã¡ã¤ã³ã«ã¼ããå§ã¾ãåã«ã SIGCHLD ã sigprocmask(2)  ã§ãããã¯ããã 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 (;;) {          /* main loop */
               /* Initialize readfds, writefds, and exceptfds
                  before the pselect() call. (Code omitted.) */

               r = pselect(nfds, &readfds, &writefds, &exceptfds,
                           NULL, &empty_mask);
               if (r == -1 && errno != EINTR) {
                   /* Handle error */
               }

               if (got_SIGCHLD) {
                   got_SIGCHLD = 0;

                   /* Handle signalled event here; e.g., wait() for all
                      terminated children. (Code omitted.) */
               }

               /* main body of program */
           }
       }

   å®ä¾
       å®éã®ã¨ãã select()  ã®å¤§äºãªç¹ã¯ä½ãªã®ãï¼ ãã£ã¹ã¯ãªãã¿ã¯å¥½ããªã¨ãã«èª‐
       ã¿æ¸ãã§ããããããªãã®ï¼ select()
       ã®éè¦ãªã¨ããã¯ãè¤æ°ã®ãã£ã¹ã¯ãªãã¿ãåæã«ç£è¦ã§ãã ãªãã®åãããªããã°ãã‐
       ã»ã¹ãé©åã«ã¹ãªã¼ãç¶æã«ç§»è¡ããã¨ããã«ããã®ã ã UNIX ããã°ã©ãã¯ã
       è¤æ°ã®ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã®å¥åºåãåæã«æ±ããã°ãªããã
       ããããã¼ã¿ã®æµãã¯éæ¬ çã§ãããã¨ããç¶æ³ã«ããåºä¼ãã åã« read(2)  ã write(2)
       ã³ã¼ã«ã®ã·ã¼ã±ã³ã¹ãä½ãã ãã§ã¯ããããã®ã³ã¼ã«ã®ã©ããã
       ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ããã®ãã¼ã¿ãå¾ã£ã¦ãããã¯ãã¦ããã
       å¥ã®ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã«ã¯ I/O ãå¯è½ãªã®ã«ä½¿ããªãã
       ã¨ãããã¨ã«ãªã£ã¦ãã¾ãã ããã select()  ã使ãã¨ãã®ç¶æ³ã«å¹æçã«å¯¾å¦ã§ããã

   SELECT ã®æ
       select()  ã使ããã¨ããå¤ãã®äººã¯ãç解ãã«ããæåã«åºããããçµæçã«
       ã§ãããã®ã¯ç§»æ¤æ§ããªãããããã¦ãã®ãªã®ãªã®ãã®ã«ãªã£ã¦ãã¾ãã ä¾ãã°ãä¸è¨ã®ãã‐
       ã°ã©ã ã¯ã éåã«å«ã¾ãããã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ãéåæ¢ (nonblocking) ã¢ã¼ã
       ã«ããªãã¦ããã©ãã«ããããã¯ãçããªããã注æãã¦æ¸ããã¦ããã å¾®å¦ãªééãã«ãã£ã¦ã
       select() ã使ãå©ç¹ã¯ç°¡åã«å¤±ããã¦ãã¾ãã ããã§ã select()
       ã³ã¼ã«ã使ãã¨ãã«æ³¨æãã¹ãéè¦äºé ãåæãã¦ãããã¨ã«ããã

       1.  select()  ã使ãã¨ãã¯ãã¿ã¤ã ã¢ã¦ãã¯è¨å®ãã¹ãã§ãªãã
           å¦çãããã¼ã¿ãç¡ãã¨ãã«ã¯ã ããªãã®ããã°ã©ã ã«ã¯ä½ããããã¨ã¯ç¡ãã¯ãã§ããã
           ã¿ã¤ã ã¢ã¦ãã«ä¾åããã³ã¼ãã¯é常移æ¤æ§ããªãã ãããã°ãé£ãããªãã

       2.  ä¸è¿°ããããã«ã å¹ççãªããã°ã©ã ãæ¸ãã«ã¯ nfds
           ã®å¤ãé©åã«è¨ç®ãã¦ä¸ããªããã°ãªããªãã

       3.  select()  ã³ã¼ã«ã®çµäºå¾ã«çµæããã§ãã¯ãã¦ã
           é©åã«å¯¾å¿ããã¤ããã®ãªããã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã¯ã ã©ã®éåã«ãå ãã¦ã¯ãªããªãã
           次ã®ã«ã¼ã«ãåç§ã

       4.  select()  ããè¿ã£ãå¾ã«ã¯ãå¨ã¦ã®éåã®å¨ã¦ã®ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã«ã¤ãã¦
           èªã¿æ¸ãå¯è½ãªç¶æã«ãªã£ã¦ãããããã§ãã¯ãã¹ãã§ããã

       5.  read(2), recv(2), write(2), send(2)
           ã¨ãã£ãé¢æ°ã¯ããã¡ããè¦æ±ããå¨ãã¼ã¿ãèªã¿æ¸ãããå¿è¦ã¯ãªãã ããå¨ãã¼ã¿ãèª‐
           ã¿æ¸ããããªããããã¯ãã©ãã£ãã¯ã®è² è·ãå°ããã
           ã¹ããªã¼ã ãéãå ´åã ããããã®æ¡ä»¶ã¯å¸¸ã«æºããããã¨ã¯éããªãã
           ãããã®é¢æ°ãé å¼µã£ã¦ã 1 ãã¤ãããéåä¿¡ã§ããªããããªå ´åã
           èæ®ã«å¥ãã¦ãããªããã°ãªããªãã

       6.  å¦çãããã¼ã¿éãå°ãããã¨ãã¯ã£ããã¨ããã£ã¦ããå ´åãé¤ãã¦ã ä¸åº¦ã« 1
           ãã¤ããã¤èªã¿æ¸ããããããªãã¨ã¯ãã¦ã¯ãªããªãã
           ãããã¡ã®è¨±ããããã®ãã¼ã¿ãã¾ã¨ãã¦èªã¿æ¸ãããªãã¨ã
           é常ã«å¹çãæªããä¸è¨ã®ä¾ã§ã¯ãããã¡ã¯ 1024 ãã¤ãã«ãã¦ãããã
           ãã®ãµã¤ãºã大ããããã®ã¯ç°¡åã ããã

       7.  read(2), recv(2), write(2), send(2)  ãªã©ã®é¢æ°ã select()
           ã³ã¼ã«ã¯ã errno ã EINTR ã EAGAIN (EWOULDBLOCK)  ã«ã㦠-1
           ãè¿ããã¨ãããã ãã®ãããªçµæã«å¯¾ãã¦é©åã«å¯¾å¿ãã¦ãããªããã°ãªããªã
           (ä¸è¨ã®ä¾ã§ã¯ãã¦ããªã)ã æ¸ãã¦ããããã°ã©ã ãã·ã°ãã«ãåããäºå®ããªããã°ã
           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()  ãå¼ã¶ãã³ã«åæåãã¹ãã§ããã OS ã«ãã£ã¦ã¯
           timeout æ§é ä½ãå¤æ´ãããå ´åãããããã§ããã ä½ãã pselect()  ã¯èªåã®
           timeout æ§é ä½ãå¤æ´ãããã¨ã¯ãªãã

       11. select()  ã¯ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿éåãå¤æ´ããã®ã§ã select() ãã«ã¼ãã®ä¸‐
           ã§ä½¿ç¨ããã¦ããå ´åã«ã¯ãå¼ã³åºããè¡ãåã«æ¯å
           ãã£ã¹ã¯ãªãã¿éåãåæåãç´ããªããã°ãªããªãã

   usleep ã¨ãã¥ã¬ã¼ã·ã§ã³
       usleep(3)  é¢æ°ãæããªãã·ã¹ãã ã§ã¯ã
       æéã®ã¿ã¤ã ã¢ã¦ããæå®ãããã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ãå¨ãã»ããããã« select()
       ãå¼ã³åºããã¨ã§ãããã代ç¨ã§ããã 以ä¸ã®ããã«ããã

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

       ä½ãããããåãã¨ä¿è¨¼ããã¦ããã®ã¯ UNIX ã·ã¹ãã ã«éãããã

è¿ãå¤
       æåããã¨ã select()  ã¯ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿éåã«æ®ã£ã¦ãã
       ãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿ã®ç·æ°ãè¿ãã

       select()  ãã¿ã¤ã ã¢ã¦ãããã¨ãè¿ãå¤ã¯ 0 ã«ãªãã
       ãã®æããã¡ã¤ã«ãã£ã¹ã¯ãªãã¿éåã¯ãã¹ã¦ç©ºã§ãã (ããããããªããªãã·ã¹ãã ããã)ã

       è¿ãå¤ã -1 ã®å ´åã¯ã¨ã©ã¼ãæå³ãã errno ãé©åã«ã»ããããããã¨ã©ã¼ãèµ·ãã£ãå ´åã
       è¿ãããéåã®å容ãæ§é ä½ struct timeout ã®å容ã¯
       æªå®ç¾©ã¨ãªã£ã¦ããã使ç¨ãã¹ãã§ã¯ãªãã ããã pselect()  ã¯æ±ºã㦠ntimeout
       ãå¤æ´ããªãã

注æ
       ä¸è¬çã«è¨ã£ã¦ãã½ã±ããããµãã¼ãããå¨ã¦ã®ãªãã¬ã¼ãã£ã³ã°ã·ã¹ãã 㯠select()
       ããµãã¼ããã¦ããã select() ã使ãã¨ããã‐
       ã°ã©ããã¹ã¬ããããã©ã¼ã¯ãIPCãã·ã°ãã«ãã¡ã¢ãªå±æã ç‐
       ãã使ã£ã¦ãã£ã¨è¤éãªæ¹æ³ã§è§£æ±ºãããã¨ããå¤ãã®åé¡ãã
       移æ¤æ§ããããã¤å¹ççãªæ¹æ³ã§è§£æ±ºã§ããã

       poll(2)  ã·ã¹ãã ã³ã¼ã«ã¯ select()  ã¨åãæ©è½ãæã£ã¦ããã
       ã¾ã°ããªãã¡ã¤ã«ãã£ã¹ã¯ãªãã¿éåãç£è¦ããå ´åã« ããããå¹çãããã
       ç¾å¨ã§ã¯åºãå©ç¨å¯è½ã§ãããã以å㯠select()  ãã移æ¤æ§ã®é¢ã§å£ã£ã¦ããã

       Linux ç¬èªã® 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 a;
           int s;
           int yes;

           if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
               perror("socket");
               return -1;
           }
           yes = 1;
           if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
                   &yes, sizeof(yes)) == -1) {
               perror("setsockopt");
               close(s);
               return -1;
           }
           memset(&a, 0, sizeof(a));
           a.sin_port = htons(listen_port);
           a.sin_family = AF_INET;
           if (bind(s, (struct sockaddr *) &a, sizeof(a)) == -1) {
               perror("bind");
               close(s);
               return -1;
           }
           printf("accepting connections on port %d\n", listen_port);
           listen(s, 10);
           return s;
       }

       static int
       connect_socket(int connect_port, char *address)
       {
           struct sockaddr_in a;
           int s;

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

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

           if (!inet_aton(address, (struct in_addr *) &a.sin_addr.s_addr)) {
               perror("bad IP address format");
               close(s);
               return -1;
           }

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

       #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, buf1_written;
           int buf2_avail, buf2_written;

           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 r, nfds = 0;
               fd_set rd, wr, er;

               FD_ZERO(&rd);
               FD_ZERO(&wr);
               FD_ZERO(&er);
               FD_SET(h, &rd);
               nfds = max(nfds, h);
               if (fd1 > 0 && buf1_avail < BUF_SIZE) {
                   FD_SET(fd1, &rd);
                   nfds = max(nfds, fd1);
               }
               if (fd2 > 0 && buf2_avail < BUF_SIZE) {
                   FD_SET(fd2, &rd);
                   nfds = max(nfds, fd2);
               }
               if (fd1 > 0 && buf2_avail - buf2_written > 0) {
                   FD_SET(fd1, &wr);
                   nfds = max(nfds, fd1);
               }
               if (fd2 > 0 && buf1_avail - buf1_written > 0) {
                   FD_SET(fd2, &wr);
                   nfds = max(nfds, fd2);
               }
               if (fd1 > 0) {
                   FD_SET(fd1, &er);
                   nfds = max(nfds, fd1);
               }
               if (fd2 > 0) {
                   FD_SET(fd2, &er);
                   nfds = max(nfds, fd2);
               }

               r = select(nfds + 1, &rd, &wr, &er, NULL);

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

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

               if (FD_ISSET(h, &rd)) {
                   unsigned int l;
                   struct sockaddr_in client_address;

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

               /* NB: read oob data before normal reads */

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

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

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

               /* check if write data has caught read data */

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

               /* one side has closed the connection, keep
                  writing to the other side until empty */

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

       ä¸è¨ã®ããã°ã©ã ã¯ãã»ã¨ãã©ã®ç¨®é¡ã® TCP æ¥ç¶ããã©ã¯ã¼ãããã telnet
       ãµã¼ãã«ãã£ã¦ä¸ç¶ããã OOB ã·ã°ãã«ãã¼ã¿ãæ±ããã ãã®ããã°ã©ã ã¯ããã¼ã¿ãã‐
       ã¼ãåæ¹åã«åæã«éãã¨ããã ãããããåé¡ãå¦çã§ããã 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)

ãã®ææ¸ã«ã¤ãã¦
       ãã® man ãã¼ã¸ã¯ Linux man-pages ããã¸ã§ã¯ãã®ãªãªã¼ã¹ 3.51 ã®ä¸é¨
       ã§ãããããã¸ã§ã¯ãã®èª¬æã¨ãã°å ±åã«é¢ããæå ±ã¯
       http://www.kernel.org/doc/man-pages/ ã«æ¸ããã¦ããã



Linux                             2012-08-03                     SELECT_TUT(2)