乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      I/O多路復用詳解(一)

       zhouADNjj 2014-04-29

      一、五種I/O模型

      1、阻塞I/O模型

           最流行的I/O模型是阻塞I/O模型,缺省情形下,所有套接口都是阻塞的。我們以數(shù)據(jù)報套接口為例來講解此模型(我們使用UDP而不是TCP作為例子的原因在于就UDP而言,數(shù)據(jù)準備好讀取的概念比較簡單:要么整個數(shù)據(jù)報已經(jīng)收到,要么還沒有。然而對于TCP來說,諸如套接口低潮標記等額外變量開始活動,導致這個概念變得復雜)。

           進程調(diào)用recvfrom,其系統(tǒng)調(diào)用直到數(shù)據(jù)報到達且被拷貝到應用進程的緩沖區(qū)中或者發(fā)生錯誤才返回,期間一直在等待。我們就說進程在從調(diào)用recvfrom開始到它返回的整段時間內(nèi)是被阻塞的。

      2、非阻塞I/O模型

            進程把一個套接口設置成非阻塞是在通知內(nèi)核:當所請求的I/O操作非得把本進程投入睡眠才能完成時,不要把本進程投入睡眠,而是返回一個錯誤。也就是說當數(shù)據(jù)沒有到達時并不等待,而是以一個錯誤返回。

      3、I/O復用模型

           調(diào)用select或poll,在這兩個系統(tǒng)調(diào)用中的某一個上阻塞,而不是阻塞于真正I/O系統(tǒng)調(diào)用。 阻塞于select調(diào)用,等待數(shù)據(jù)報套接口可讀。當select返回套接口可讀條件時,調(diào)用recevfrom將數(shù)據(jù)報拷貝到應用緩沖區(qū)中。

      4、信號驅(qū)動I/O模型

           首先開啟套接口信號驅(qū)動I/O功能, 并通過系統(tǒng)調(diào)用sigaction安裝一個信號處理函數(shù)(此系統(tǒng)調(diào)用立即返回,進程繼續(xù)工作,它是非阻塞的)。當數(shù)據(jù)報準備好被讀時,就為該進程生成一個SIGIO信號。隨即可以在信號處理程序中調(diào)用recvfrom來讀數(shù)據(jù)報,井通知主循環(huán)數(shù)據(jù)已準備好被處理中。也可以通知主循環(huán),讓它來讀數(shù)據(jù)報。

      5、異步I/O模型

           告知內(nèi)核啟動某個操作,并讓內(nèi)核在整個操作完成后(包括將數(shù)據(jù)從內(nèi)核拷貝到用戶自己的緩沖區(qū))通知我們。這種模型與信號驅(qū)動模型的主要區(qū)別是:
                 信號驅(qū)動I/O:由內(nèi)核通知我們何時可以啟動一個I/O操作,
                 異步I/O模型:由內(nèi)核通知我們I/O操作何時完成。

       

      二、I/O復用的典型應用場合:

       1、當客戶處理多個描述字(通常是交互式輸入和網(wǎng)絡套接口)時,必須使用I/O復用。

       2、如果一個服務器要處理多個服務或者多個協(xié)議(例如既要處理TCP,又要處理UDP),一般就要使用I/O復用。

       

      三、支持I/O復用的系統(tǒng)調(diào)用

           目前支持I/O復用的系統(tǒng)調(diào)用有select、pselect、poll、epoll:

      1、select函數(shù)

           該函數(shù)允許進程指示內(nèi)核等待多個事件中的任何一個發(fā)生,并僅在有一個或多個事件發(fā)生或經(jīng)歷一段指定的時間后才喚醒它。

      格式為:

      #include <sys/select.h>
      #include <sys/time.h>

      int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);
                
               返回:就緒描述字的正數(shù)目,0-超時,-1-出錯


      我們從該函數(shù)的最后一個參數(shù)開始介紹,它告知內(nèi)核等待所指定描述字中的任何一個就緒可花多少時間。其timeval結(jié)構(gòu)用于指定這段時間的秒數(shù)和微秒數(shù)。

               struct timeval{

                         long tv_sec;   //seconds

                         long tv_usec;  //microseconds

             };

      這個參數(shù)有三種可能:

      (1)永遠等待下去:僅在有一個描述字準備好I/O時才返回。為此,我們把該參數(shù)設置為空指針。

      (2)等待一段固定時間:在有一個描述字準備好I/O時返回,但是不超過由該參數(shù)所指向的timeval結(jié)構(gòu)中指定的秒數(shù)和微秒數(shù)。

      (3)根本不等待:檢查描述字后立即返回,這稱為輪詢。為此,該參數(shù)必須指向一個timeval結(jié)構(gòu),而且其中的定時器值必須為0。

          中間的三個參數(shù)readset、writeset和exceptset指定我們要讓內(nèi)核測試讀、寫和異常條件的描述字。如果我們對某一個的條件不感興趣,就可以把它設為空指針。struct fd_set可以理解為一個集合,這個集合中存放的是文件描述符,可通過以下四個宏進行設置:

                void FD_ZERO(fd_set *fdset);           //清空集合

                void FD_SET(int fd, fd_set *fdset);   //將一個給定的文件描述符加入集合之中

                void FD_CLR(int fd, fd_set *fdset);   //將一個給定的文件描述符從集合中刪除

                int FD_ISSET(int fd, fd_set *fdset);   // 檢查集合中指定的文件描述符是否可以讀寫 ?

      目前支持的異常條件只有兩個:

      (1)某個套接口的帶外數(shù)據(jù)的到達。

      (2)某個已置為分組方式的偽終端存在可從其主端讀取的控制狀態(tài)信息。

          第一個參數(shù)maxfdp1指定待測試的描述字個數(shù),它的值是待測試的最大描述字加1(因此我們把該參數(shù)命名為maxfdp1),描述字0、1、2...maxfdp1-1均將被測試。

       一個應用select的例子:

      /**
        *TCP回射服務器客戶端程序
        */

      #include <stdio.h>
      #include <stdlib.h>
      #include <unistd.h>
      #include <sys/socket.h>
      #include <sys/types.h>
      #include <netinet/in.h>
      #include <netdb.h>
      #include <string.h>
      #include <math.h>
      #include <sys/select.h>
      #include <sys/time.h>

      #define SERVER_PORT 3333 //服務器端口號


      void str_cli(FILE *fp, int sockfd)
      {
          int maxfdp1, stdineof;
          fd_set rset;
          char buf[BUFSIZ];
          int n;

          stdineof = 0;
          FD_ZERO(&rset);

          while(1)
          {
              if( stdineof == 0 )
                  FD_SET(fileno(fp),&rset);
              FD_SET(sockfd, &rset);

              maxfdp1 = ((fileno(fp) > sockfd) ? fileno(fp) : sockfd) + 1;

              select(maxfdp1, &rset, NULL, NULL, NULL);

              if( FD_ISSET(sockfd, &rset) )
              {
                  if( (n = read(sockfd, buf, BUFSIZ)) == 0 )
                      if( stdineof == 1 )
                          return;
                      else
                          perror("server terminated prematurely");
                  write(fileno(stdout), buf, n);
              }

              if( FD_ISSET(fileno(fp), &rset))
              {
                  if( (n = read(fileno(fp), buf, BUFSIZ)) == 0 )
                  {
                      stdineof = 1;
                      shutdown(sockfd, SHUT_WR);
                      FD_CLR(fileno(fp), &rset);
                      continue;
                  }
                  write(sockfd, buf, n);
              }
          }
      }

      int main(int argc, char *argv[])
      {
          int sockfd[5];
          struct sockaddr_in servaddr;
          struct hostent *hp;
          char buf[BUFSIZ];

          if( argc != 2 )
          {
              printf("Please input %s <hostname>\n", argv[0]);
              exit(1);
          }
          
          int i;
          for(i = 0; i < 5; ++i)
          {

              //創(chuàng)建socket

              if( (sockfd[i] = socket(AF_INET, SOCK_STREAM,0)) < 0 )
              {
                  printf("Create socket error!\n");
                  exit(1);
              }

              //設置服務器地址結(jié)構(gòu)

              bzero(&servaddr, sizeof(servaddr));
              servaddr.sin_family = AF_INET;
              if( (hp = gethostbyname(argv[1])) != NULL )
              {
                  bcopy(hp->h_addr, (struct sockaddr*)&servaddr.sin_addr, hp->h_length);
              }
              else if(inet_aton(argv[1], &servaddr.sin_addr) < 0 )
              {
                  printf("Input Server IP error!\n");
                  exit(1);
              }
              servaddr.sin_port = htons(SERVER_PORT);

              //連接服務器

              if( connect(sockfd[i],(struct sockaddr*)&servaddr, sizeof(servaddr)) < 0 )
              {
                  printf("Connect server failure!\n");
                  exit(1);
              }
          }
          str_cli(stdin, sockfd[0]);

          exit(0);
      }


        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多