• linux下多路复用模型之Select模型


    Linux关于并发网络分为Apache模型(Process per Connection (进程连接) ) 和TPC , 还有select模型,以及poll模型(一般是Epoll模型)

     Select模型极其作用:这文章讲述的很好,没必要重述已有的东西,就直接给链接

              http://blog.csdn.net/turkeyzhou/article/details/8609360

            我的理解:

     1 /* According to POSIX.1-2001 */
     2 #include <sys/select.h>
     3 
     4 /* According to earlier standards */
     5 #include <sys/time.h>
     6 #include <sys/types.h>
     7 #include <unistd.h>
     8 
     9 int select(int nfds, fd_set *readfds, fd_set *writefds,
    10 fd_set *exceptfds, struct timeval *timeout);
    11 
    12 void FD_CLR(int fd, fd_set *set);
    13 int FD_ISSET(int fd, fd_set *set);
    14 void FD_SET(int fd, fd_set *set);
    15 void FD_ZERO(fd_set *set);

        对于

       int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
    第一个参数 nfds: 第n个文件id的编号 (linux下,一切皆文件) 需要注意的是: nfds = fd+1 (fd 为 FD_SET中的fd)
    第二个参数: fd_set *readfds 读取文件编号,如果不需要读取的话 可以设置为NULL
    第三 ,四个参数: 同上
    第五个参数:为一个定义超时的结构体
    1        struct timeval {
    2                time_t         tv_sec;     /* seconds */
    3                suseconds_t    tv_usec;    /* microseconds */
    4            };
    
    

             该结构用来设定多少时间为超时 ,比如

    struct timeval ss ;
       ss.tv_sec  =3;
       ss.tv_usec =0; 
    //表示设定为3秒后为超时,select将会返回0
    对于下面这几个函数:

        1 void FD_CLR(int fd, fd_set *set); 

          用来清除fd的fd_set  ,比如fd为5  ,则表示set集中所有设定等于5的fd_set 都将被清除

     1 int FD_ISSET(int fd, fd_set *set); 

         判断是否set 与fd是否绑定,如果没有绑定,则返回false,如果绑定了则返回True

    void FD_SET(int fd, fd_set *set);

            将fd值 和set绑定 

    void FD_ZERO(fd_set *set);

       将set集全部清除

    简单的例子:

    判断是否有数据输入,有则直接打印出来

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<sys/select.h>
     4 #include<unistd.h>
     5 #include<sys/time.h>
     6 #include<sys/types.h>
     7 #define maxn 6
     8 #define EXIT_FAILURE  -1
     9 #define EXIT_SUCCESS   0
    10 
    11 int main(int argc , char * argv []){
    12 
    13    fd_set mtfd ;
    14    int ffd =0;
    15    struct timeval  outtime ;
    16    int retval  ;
    17    char redbuf[maxn];
    18 
    19    FD_ZERO(&mtfd);
    20    FD_SET(ffd , &mtfd);
    21 
    22 // wait up to 5.5 s
    23    outtime.tv_sec = 5 ;
    24    outtime.tv_usec = 500 ;
    25    retval = select(ffd+1 , &mtfd ,NULL , NULL , &outtime);
    26    if(-1 == retval )
    27    {
    28      printf("error happened ! %d 
    " ,__LINE__ );
    29      return EXIT_FAILURE ;
    30    }
    31    else if(0 == retval ){
    32       printf(" timeout !!  %d 
    " ,__LINE__ );
    33      return  EXIT_FAILURE ;
    34     }
    35    //means that is good !
    36 
    37      printf("retval  =  %d 
    ", retval);
    38 
    39     if( FD_ISSET(ffd , &mtfd) ){
    40 
    41         memset(redbuf ,0 , sizeof(redbuf));
    42         printf("reading ... !! ");
    43        // read(1 , redbuf ,sizeof(redbuf) ); //use the sys func
    44        fread(redbuf , sizeof(redbuf) ,ffd+1 , stdin );
    45 }
    46     //  fwrite(redbuf ,strlen(redbuf) , 1 , stdout );  
    47    //  write(1 , redbuf , strlen(redbuf)); 
    48      printf("buf = %s    buf_len = %d 
    " , redbuf , strlen(redbuf));
    49 
    50     return EXIT_SUCCESS ;
    51 }
    View Code

    makefile文件:

        

     1 .SUFFIXES: .o.c
     2 CC =gcc
     3 SRC = Se_keyboard.c
     4 OBJ = $(SRC: .c =.o)
     5 BIN = Se_keyboard
     6 
     7 
     8 .PHONY: start
     9 start:  $(OBJ)
    10         $(CC) -o $(BIN) $(OBJ)
    11 .o.c: $(SRC)
    12         $(CC) -g -Wall $@ -c  $<
    13 .PHONY: clean
    14 clean:
    15         rm -f $(OBJ)                    

     

      虽然知道这么多,但是还是觉得Select并没有什么作用。

       Select一般是和Socket搭配使用,相当于线程池的效果,但是线程池有缺点,详情看这儿:

           http://blog.csdn.net/tianmohust/article/details/6677985

           http://blog.csdn.net/xifeijian/article/details/17385831

      关于Select的原理图:

          首先来看下一对一的socket的c/s模式

          

     关于socket的一对一的详解

     http://www.cnblogs.com/gongxijun/p/4592864.html  

     看完这个之后,我们现在可以来看看这个图:

         

    下面为举例:  

              服务器创建一个socket并bind绑定一个本机地址和设定一个端口,然后进入listen监听状态。采用select模型而非传统apache模型(ppc)或者tpc模型 。 不过Select模型就是有这样一个特点

      一般我们default默认的SOMAXCONN为128 当然我们可以另外取一个设定(下面我们设定的是2048)作为最大连接数,虽然可以设置更大,但是缺点是,select模型是一个轮询模式,就是每一个都需要遍历一边所有的链接的fd

      查看是否在fd_set集合中,这样,当SOMAXCONN取值非常大时,对于每一个客户端,访问时间都会延迟一点点,这样就是效率不是特别高!

     下面是一个简单的多路复用的网络并发Select模型

       

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<stdlib.h>
      4 #include<unistd.h>
      5 #include<netinet/in.h>
      6 #include<netinet/ip.h>
      7 #include<sys/socket.h>
      8 #include<sys/types.h>
      9 #include<sys/time.h>
     10 #include<arpa/inet.h>
     11 #include<sys/select.h>
     12 #include<assert.h>
     13 
     14 #ifndef  EXIT_SUCCESS
     15 #define EXIT_SUCCESS 0
     16 #endif
     17 
     18 #ifndef  EXIT_FAILURE
     19 #define EXIT_FAILURE -1
     20 #endif
     21 
     22 #define Max_connect 2048    //usually is SOMAXCONN =128 ,can be change
     23 
     24 #define maxn 1024
     25 #define Port 5567
     26 #define Ser_addr "192.168.132.128"
     27 
     28 #define ERROR_EXIT( inf ) 
     29   do{    
     30      perror( inf );  
     31      printf("it happened in %d 
    ", __LINE__); 
     32      exit(-1); 
     33   }while(0);
     34 
     35 #define  Waring( inf ) 
     36 do{    
     37      perror( inf );  
     38      printf("it happened in %d 
    ", __LINE__); 
     39   }while(0);
     40 
     41 
     42 int fds[Max_connect];
     43 int cnt = 1;
     44 
     45 void
     46 print (int fd, const char *str)
     47 {
     48   assert (str != NULL);
     49   printf ("the fd is %d 
    ", fd);
     50   puts (str);
     51 }
     52 
     53 int
     54 main (int argv, char *argc[])
     55 {
     56 
     57   int ser_sfd = -1, i;
     58   struct sockaddr_in ser_addr;
     59   struct sockaddr_in client_addr;
     60   int setfd = 0, optval, maxsockfd;
     61 
     62   char rebuf[maxn], wbuf[maxn];
     63 
     64   // build a socket with ipv4 ans tcp 
     65 
     66   if ((ser_sfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
     67     ERROR_EXIT ("socket...!");
     68 
     69   // set the type socket
     70   /*
     71      level ={ SOL_SOCKET ,IPPROTO_TCP}
     72      setsockopt is to cancle the jiangsi process
     73    */
     74 
     75   printf ("ser_sfd = %d  
    ", ser_sfd);
     76   if (setsockopt (ser_sfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval))
     77       < 0)
     78     ERROR_EXIT ("setsockopt...!");
     79 
     80   memset (&client_addr, 0, sizeof (client_addr));
     81   memset (&ser_addr, 0, sizeof (ser_addr));
     82   ser_addr.sin_family = AF_INET;
     83   ser_addr.sin_port = htons (Port);
     84   ser_addr.sin_addr.s_addr = htonl (INADDR_ANY);
     85 
     86   if (bind (ser_sfd, (struct sockaddr *) &ser_addr, sizeof (ser_addr)) < 0)
     87     ERROR_EXIT ("bind..!");
     88 
     89   if (listen (ser_sfd, Max_connect) < 0)
     90     ERROR_EXIT ("listen...!");
     91 
     92   //user the select moduel
     93   memset (fds, 0, sizeof (fds));
     94   fd_set fdset, wfd;
     95   maxsockfd = ser_sfd;        //max socket fd
     96 
     97   struct timeval tout;
     98 
     99   tout.tv_sec = 15;
    100   tout.tv_usec = 0;
    101 
    102 
    103   while (1)
    104     {
    105 
    106       FD_ZERO (&fdset);        //clear  
    107       //FD_ZERO (&wfd);
    108 
    109       FD_SET (ser_sfd, &fdset);    //bind
    110       //FD_SET (ser_sfd, &wfd);
    111 
    112       struct timeval tout;
    113 
    114       tout.tv_sec = 15;
    115       tout.tv_usec = 0;
    116 
    117 
    118       for (i = 0; i < cnt; i++)
    119     {
    120       if (fds[i] != 0)
    121         FD_SET (fds[i], &fdset);
    122     }
    123 
    124       int tag = select (maxsockfd + 1, &fdset, NULL, NULL, &tout);
    125 
    126       if (tag == 0)
    127     {
    128       Waring ("select wait timeout !");
    129       continue;
    130     }
    131       else if (tag == -1)
    132     ERROR_EXIT ("Error select ...!");
    133 
    134       //lunxun select
    135       for (i = 0; i < cnt; i++)
    136     {
    137 
    138       if (FD_ISSET (fds[i], &fdset))
    139         {
    140 
    141           int len = recv (fds[i], rebuf, sizeof (rebuf), 0);
    142           if (len <= 0)
    143         {
    144 
    145           printf ("%d: 
    ", fds[i]);
    146           close (fds[i]);
    147           FD_CLR (fds[i], &fdset);
    148           Waring ("client is closed !");
    149           continue;
    150         }
    151 
    152           printf ("the client_ip : %s
    ",
    153               inet_ntoa (client_addr.sin_addr));
    154 
    155           print (fds[i], rebuf);
    156 
    157           send (fds[i], rebuf, sizeof (rebuf), 0);    //hui she
    158           memset (rebuf, 0, sizeof (rebuf));
    159         }
    160     }
    161       //if have a new connect happened
    162       //  memset(&client_addr , 0 ,sizeof(client_addr)); 
    163       if (FD_ISSET (ser_sfd, &fdset))
    164     {
    165       // memset(&client_addr , 0 ,sizeof(client_addr));
    166       int acplen = sizeof (client_addr);
    167       int acp = accept (ser_sfd, (struct sockaddr *) &client_addr,
    168                 &acplen);
    169 
    170       printf ("accept return acp=%d 
    ", acp);
    171 
    172       if (acp < 0)
    173         {
    174 
    175           Waring ("waring accept acp<=0!");
    176           continue;
    177         }
    178       //add to arr
    179       if (cnt < maxn)
    180         fds[cnt++] = acp;
    181       else
    182         {
    183           ERROR_EXIT ("cnt>maxn");
    184         }
    185       if (acp > maxsockfd)
    186         maxsockfd = acp;
    187     }
    188     }
    189 
    190   for (i = 0; i < cnt; i++)
    191     {
    192       close (fds[i]);
    193     }
    194 
    195   return EXIT_SUCCESS;
    196 }

    makefile文件:
      

     1 .SUFFIXES: .o.c 
     2 CC =gcc
     3 SRC =  server.c
     4 OBJ = $(SRC: .c =.o) 
     5 BIN = Sez_Server
     6 
     7 
     8 .PHONY: start
     9 start:  $(OBJ)
    10     $(CC) -o $(BIN) $(OBJ)
    11 .o.c: $(SRC)
    12     $(CC) -g -Wall $@ -c  $<
    13 .PHONY: clean
    14 clean:
    15     rm -f $(OBJ)

    客户端:

        

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<stdlib.h>
     4 #include<netinet/in.h>
     5 #include<arpa/inet.h>
     6 #include<sys/socket.h>
     7 #include<sys/types.h>
     8 #include<assert.h>
     9 #include<unistd.h>
    10 #ifndef EXIT_FAILURE
    11 #define EXIT_FAILURE  -1    //exit failure
    12 #endif
    13 #ifndef EXIT_SUCCESS
    14 #define EXIT_SUCCESS   0    // exit sucessful
    15 #endif
    16 
    17 #define Port 5567
    18 #define IPADDR  "192.168.132.128"
    19 #define maxn 1024
    20 
    21 #define ERROR_EXIT( inf ) 
    22  do{  
    23    perror( inf ); 
    24    printf("it's happened in %d 
    ",__LINE__); 
    25    }while(0) ;
    26 
    27 
    28  //use the function to connect the server !!
    29 
    30 
    31 int
    32 main (int argv, char *argc[])
    33 {
    34 
    35   int sfd = -1;
    36   char rbuf[maxn], wbuf[maxn];
    37   // int sfd=-1 ; //socket_fd
    38   int confd = -1;        //connect_fd
    39   struct sockaddr_in soaddr;
    40   if ((sfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    41     {
    42       ERROR_EXIT ("socket");
    43       return EXIT_FAILURE;
    44     }
    45 
    46   //memset  a struct    
    47   memset (&soaddr, 0, sizeof (soaddr));
    48 
    49   //int the struct sockaddr_in
    50 
    51   soaddr.sin_family = AF_INET;
    52   soaddr.sin_port = htons (Port);
    53   soaddr.sin_addr.s_addr = inet_addr (IPADDR);
    54 
    55   if ((confd =
    56        connect (sfd, (struct sockadrr *) &soaddr, sizeof (soaddr))) < 0)
    57     {
    58       ERROR_EXIT ("connect");
    59       return EXIT_FAILURE;
    60     }
    61 
    62   printf ("connect is sucessful !
    ");
    63 
    64   while (fgets (wbuf, sizeof (rbuf), stdin) != NULL)
    65     {
    66       write (sfd, wbuf, strlen (wbuf));
    67       read (sfd, rbuf, sizeof (rbuf));
    68       fputs (rbuf, stdout);
    69     }
    70 
    71   close (sfd);
    72   close (confd);
    73   return EXIT_SUCCESS;
    74 }

    makefile文件:

    1.     
       1 .SUFFIXES: .o.c 
       2 CC =gcc
       3 SRC = client.c
       4 OBJ = $(SRC: .c =.o) 
       5 BIN = Se_client
       6 
       7 
       8 .PHONY: start
       9 start:  $(OBJ)
      10     $(CC) -o $(BIN) $(OBJ)
      11 .o.c: $(SRC)
      12     $(CC) -g -Wall $@ -c  $<
      13 .PHONY: clean
      14 clean:
      15     rm -f $(OBJ)

      效果图:

    2.   

         

  • 相关阅读:
    C#托盘图标
    线程相关整理
    Quartz.NET 快速入门
    (转)IE内存泄露,iframe内存泄露造成的原因和解决方案
    美化console.log的文本(转载)
    mongoDB学习资料整理
    EF7学习资料整理
    Oracle常用
    Node.js学习资料整理
    【大型网站技术实践】初级篇:借助Nginx搭建反向代理服务器(转)
  • 原文地址:https://www.cnblogs.com/gongxijun/p/4702738.html
Copyright © 2020-2023  润新知