<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      IO多路復用之select總結

      1、基本概念

        IO多路復用是指內核一旦發現進程指定的一個或者多個IO條件準備讀取,它就通知該進程。IO多路復用適用如下場合:

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

        (2)當一個客戶同時處理多個套接口時,而這種情況是可能的,但很少出現。

        (3)如果一個TCP服務器既要處理監聽套接口,又要處理已連接套接口,一般也要用到I/O復用。

        (4)如果一個服務器即要處理TCP,又要處理UDP,一般要使用I/O復用。

        (5)如果一個服務器要處理多個服務或多個協議,一般要使用I/O復用。

        與多進程和多線程技術相比,I/O多路復用技術的最大優勢是系統開銷小,系統不必創建進程/線程,也不必維護這些進程/線程,從而大大減小了系統的開銷。

      2、select函數

        該函數準許進程指示內核等待多個事件中的任何一個發送,并只在有一個或多個事件發生或經歷一段指定的時間后才喚醒。函數原型如下:

      #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)
      返回值:就緒描述符的數目,超時返回0,出錯返回-1

      函數參數介紹如下:

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

      因為文件描述符是從0開始的。

      (2)中間的三個參數readset、writeset和exceptset指定我們要讓內核測試讀、寫和異常條件的描述字。如果對某一個的條件不感興趣,就可以把它設為空指針。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);   // 檢查集合中指定的文件描述符是否可以讀寫 

      (3)timeout告知內核等待所指定描述字中的任何一個就緒可花多少時間。其timeval結構用于指定這段時間的秒數和微秒數。

               struct timeval{

                         long tv_sec;   //seconds

                         long tv_usec;  //microseconds

             };

      這個參數有三種可能:

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

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

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

       原理圖:

      3、測試程序

        寫一個TCP回射程序,程序的功能是:客戶端向服務器發送信息,服務器接收并原樣發送給客戶端,客戶端顯示出接收到的信息。

      服務端程序如下:

        1 #include <stdio.h>
        2 #include <stdlib.h>
        3 #include <string.h>
        4 #include <errno.h>
        5 #include <netinet/in.h>
        6 #include <sys/socket.h>
        7 #include <sys/select.h>
        8 #include <sys/types.h>
        9 #include <netinet/in.h>
       10 #include <arpa/inet.h>
       11 #include <unistd.h>
       12 #include <assert.h>
       13 
       14 #define IPADDR      "127.0.0.1"
       15 #define PORT        8787
       16 #define MAXLINE     1024
       17 #define LISTENQ     5
       18 #define SIZE        10
       19 
       20 typedef struct server_context_st
       21 {
       22     int cli_cnt;        /*客戶端個數*/
       23     int clifds[SIZE];   /*客戶端的個數*/
       24     fd_set allfds;      /*句柄集合*/
       25     int maxfd;          /*句柄最大值*/
       26 } server_context_st;
       27 static server_context_st *s_srv_ctx = NULL;
       28 /*===========================================================================
       29  * ==========================================================================*/
       30 static int create_server_proc(const char* ip,int port)
       31 {
       32     int  fd;
       33     struct sockaddr_in servaddr;
       34     fd = socket(AF_INET, SOCK_STREAM,0);
       35     if (fd == -1) {
       36         fprintf(stderr, "create socket fail,erron:%d,reason:%s\n",
       37                 errno, strerror(errno));
       38         return -1;
       39     }
       40 
       41     /*一個端口釋放后會等待兩分鐘之后才能再被使用,SO_REUSEADDR是讓端口釋放后立即就可以被再次使用。*/
       42     int reuse = 1;
       43     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
       44         return -1;
       45     }
       46 
       47     bzero(&servaddr,sizeof(servaddr));
       48     servaddr.sin_family = AF_INET;
       49     inet_pton(AF_INET,ip,&servaddr.sin_addr);
       50     servaddr.sin_port = htons(port);
       51 
       52     if (bind(fd,(struct sockaddr*)&servaddr,sizeof(servaddr)) == -1) {
       53         perror("bind error: ");
       54         return -1;
       55     }
       56 
       57     listen(fd,LISTENQ);
       58 
       59     return fd;
       60 }
       61 
       62 static int accept_client_proc(int srvfd)
       63 {
       64     struct sockaddr_in cliaddr;
       65     socklen_t cliaddrlen;
       66     cliaddrlen = sizeof(cliaddr);
       67     int clifd = -1;
       68 
       69     printf("accpet clint proc is called.\n");
       70 
       71 ACCEPT:
       72     clifd = accept(srvfd,(struct sockaddr*)&cliaddr,&cliaddrlen);
       73 
       74     if (clifd == -1) {
       75         if (errno == EINTR) {
       76             goto ACCEPT;
       77         } else {
       78             fprintf(stderr, "accept fail,error:%s\n", strerror(errno));
       79             return -1;
       80         }
       81     }
       82 
       83     fprintf(stdout, "accept a new client: %s:%d\n",
       84             inet_ntoa(cliaddr.sin_addr),cliaddr.sin_port);
       85 
       86     //將新的連接描述符添加到數組中
       87     int i = 0;
       88     for (i = 0; i < SIZE; i++) {
       89         if (s_srv_ctx->clifds[i] < 0) {
       90             s_srv_ctx->clifds[i] = clifd;
       91             s_srv_ctx->cli_cnt++;
       92             break;
       93         }
       94     }
       95 
       96     if (i == SIZE) {
       97         fprintf(stderr,"too many clients.\n");
       98         return -1;
       99     }
      100
      101 }
      102 
      103 static int handle_client_msg(int fd, char *buf) 
      104 {
      105     assert(buf);
      106     printf("recv buf is :%s\n", buf);
      107     write(fd, buf, strlen(buf) +1);
      108     return 0;
      109 }
      110 
      111 static void recv_client_msg(fd_set *readfds)
      112 {
      113     int i = 0, n = 0;
      114     int clifd;
      115     char buf[MAXLINE] = {0};
      116     for (i = 0;i <= s_srv_ctx->cli_cnt;i++) {
      117         clifd = s_srv_ctx->clifds[i];
      118         if (clifd < 0) {
      119             continue;
      120         }
      121         /*判斷客戶端套接字是否有數據*/
      122         if (FD_ISSET(clifd, readfds)) {
      123             //接收客戶端發送的信息
      124             n = read(clifd, buf, MAXLINE);
      125             if (n <= 0) {
      126                 /*n==0表示讀取完成,客戶都關閉套接字*/
      127                 FD_CLR(clifd, &s_srv_ctx->allfds);
      128                 close(clifd);
      129                 s_srv_ctx->clifds[i] = -1;
      130                 continue;
      131             }
      132             handle_client_msg(clifd, buf);
      133         }
      134     }
      135 }
      136 static void handle_client_proc(int srvfd)
      137 {
      138     int  clifd = -1;
      139     int  retval = 0;
      140     fd_set *readfds = &s_srv_ctx->allfds;
      141     struct timeval tv;
      142     int i = 0;
      143 
      144     while (1) {
      145         /*每次調用select前都要重新設置文件描述符和時間,因為事件發生后,文件描述符和時間都被內核修改啦*/
      146         FD_ZERO(readfds);
      147         /*添加監聽套接字*/
      148         FD_SET(srvfd, readfds);
      149         s_srv_ctx->maxfd = srvfd;
      150 
      151         tv.tv_sec = 30;
      152         tv.tv_usec = 0;
      153         /*添加客戶端套接字*/
      154         for (i = 0; i < s_srv_ctx->cli_cnt; i++) {
      155             clifd = s_srv_ctx->clifds[i];
      156             /*去除無效的客戶端句柄*/
      157             if (clifd != -1) {
      158                 FD_SET(clifd, readfds);
      159             }
      160             s_srv_ctx->maxfd = (clifd > s_srv_ctx->maxfd ? clifd : s_srv_ctx->maxfd);
      161         }
      162 
      163         /*開始輪詢接收處理服務端和客戶端套接字*/
      164         retval = select(s_srv_ctx->maxfd + 1, readfds, NULL, NULL, &tv);
      165         if (retval == -1) {
      166             fprintf(stderr, "select error:%s.\n", strerror(errno));
      167             return;
      168         }
      169         if (retval == 0) {
      170             fprintf(stdout, "select is timeout.\n");
      171             continue;
      172         }
      173         if (FD_ISSET(srvfd, readfds)) {
      174             /*監聽客戶端請求*/
      175             accept_client_proc(srvfd);
      176         } else {
      177             /*接受處理客戶端消息*/
      178             recv_client_msg(readfds);
      179         }
      180     }
      181 }
      182 
      183 static void server_uninit()
      184 {
      185     if (s_srv_ctx) {
      186         free(s_srv_ctx);
      187         s_srv_ctx = NULL;
      188     }
      189 }
      190 
      191 static int server_init()
      192 {
      193     s_srv_ctx = (server_context_st *)malloc(sizeof(server_context_st));
      194     if (s_srv_ctx == NULL) {
      195         return -1;
      196     }
      197 
      198     memset(s_srv_ctx, 0, sizeof(server_context_st));
      199 
      200     int i = 0;
      201     for (;i < SIZE; i++) {
      202         s_srv_ctx->clifds[i] = -1;
      203     }
      204 
      205     return 0;
      206 }
      207 
      208 int main(int argc,char *argv[])
      209 {
      210     int  srvfd;
      211     /*初始化服務端context*/
      212     if (server_init() < 0) {
      213         return -1;
      214     }
      215     /*創建服務,開始監聽客戶端請求*/
      216     srvfd = create_server_proc(IPADDR, PORT);
      217     if (srvfd < 0) {
      218         fprintf(stderr, "socket create or bind fail.\n");
      219         goto err;
      220     }
      221     /*開始接收并處理客戶端請求*/
      222     handle_client_proc(srvfd);
      223     server_uninit();
      224     return 0;
      225 err:
      226     server_uninit();
      227     return -1;
      228 }

      客戶端程序如下:

       1 #include <netinet/in.h>
       2 #include <sys/socket.h>
       3 #include <stdio.h>
       4 #include <string.h>
       5 #include <stdlib.h>
       6 #include <sys/select.h>
       7 #include <time.h>
       8 #include <unistd.h>
       9 #include <sys/types.h>
      10 #include <errno.h>
      11 
      12 #define MAXLINE 1024
      13 #define IPADDRESS "127.0.0.1"
      14 #define SERV_PORT 8787
      15 
      16 #define max(a,b) (a > b) ? a : b
      17 
      18 static void handle_recv_msg(int sockfd, char *buf) 
      19 {
      20 printf("client recv msg is:%s\n", buf);
      21 sleep(5);
      22 write(sockfd, buf, strlen(buf) +1);
      23 }
      24 
      25 static void handle_connection(int sockfd)
      26 {
      27 char sendline[MAXLINE],recvline[MAXLINE];
      28 int maxfdp,stdineof;
      29 fd_set readfds;
      30 int n;
      31 struct timeval tv;
      32 int retval = 0;
      33 
      34 while (1) {
      35 
      36 FD_ZERO(&readfds);
      37 FD_SET(sockfd,&readfds);
      38 maxfdp = sockfd;
      39 
      40 tv.tv_sec = 5;
      41 tv.tv_usec = 0;
      42 
      43 retval = select(maxfdp+1,&readfds,NULL,NULL,&tv);
      44 
      45 if (retval == -1) {
      46 return ;
      47 }
      48 
      49 if (retval == 0) {
      50 printf("client timeout.\n");
      51 continue;
      52 }
      53 
      54 if (FD_ISSET(sockfd, &readfds)) {
      55 n = read(sockfd,recvline,MAXLINE);
      56 if (n <= 0) {
      57 fprintf(stderr,"client: server is closed.\n");
      58 close(sockfd);
      59 FD_CLR(sockfd,&readfds);
      60 return;
      61 }
      62 
      63 handle_recv_msg(sockfd, recvline);
      64 }
      65 }
      66 }
      67 
      68 int main(int argc,char *argv[])
      69 {
      70 int sockfd;
      71 struct sockaddr_in servaddr;
      72 
      73 sockfd = socket(AF_INET,SOCK_STREAM,0);
      74 
      75 bzero(&servaddr,sizeof(servaddr));
      76 servaddr.sin_family = AF_INET;
      77 servaddr.sin_port = htons(SERV_PORT);
      78 inet_pton(AF_INET,IPADDRESS,&servaddr.sin_addr);
      79 
      80 int retval = 0;
      81 retval = connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
      82 if (retval < 0) {
      83 fprintf(stderr, "connect fail,error:%s\n", strerror(errno));
      84 return -1;
      85 }
      86 
      87 printf("client send to server .\n");
      88 write(sockfd, "hello server", 32);
      89 
      90 handle_connection(sockfd);
      91 
      92 return 0;
      93 }

       

      4、程序結果

        啟動服務程序,執行三個個客戶程序進行測試,結果如下圖所示:

      參考:

      http://konglingchun.is-programmer.com/posts/12146.html

      http://blog.163.com/smileface100@126/blog/static/27720874200951024532966/

      備注:

      (1)2016-10-23修改服務端,添加注釋,非法客戶端的處理。

      posted @ 2013-08-14 23:07  Rabbit_Dale  閱讀(161127)  評論(30)    收藏  舉報
      主站蜘蛛池模板: 国产精品午夜福利片国产| 国产熟睡乱子伦视频在线播放| 人妻加勒比系列无码专区| 无码精品人妻一区二区三区中| 国产精品久久久久7777| 国产综合久久久久鬼色| 影音先锋女人AA鲁色资源| 国产日韩一区二区在线| 92自拍视频爽啪在线观看| 国产精品污双胞胎在线观看| 一区二区三区av天堂| 色成年激情久久综合国产| 无码国产精品一区二区免费式芒果| 日本久久香蕉一本一道| 新久久国产色av免费看| 白丝乳交内射一二三区| 国产精品久久久久久久9999 | 中文字幕在线日韩| 日本高清www无色夜在线视频| 大地资源中文第二页日本| 国产精品一区二区久久精品| 久久精品国产99久久无毒不卡| 欧美成人精品三级网站| 国产亚洲一二三区精品| 少妇无码太爽了在线播放| 国产av综合影院| 377p日本欧洲亚洲大胆张筱雨| 不卡国产一区二区三区| 亚洲精品久荜中文字幕| yw尤物av无码国产在线观看| 亚洲精品成a人在线观看| 国产对白老熟女正在播放| 男女性高爱潮免费网站| 亚洲一区二区三区18禁| 在线天堂中文新版www| 蜜臀av午夜精品福利| 国产精品久久蜜臀av| 墨脱县| 欧洲亚洲成av人片天堂网| 农村熟女大胆露脸自拍| 亚洲一区二区中文字幕|