您当前的位置: 首页 >  linux

phymat.nico

暂无认证

  • 0浏览

    0关注

    1967博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

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

phymat.nico 发布时间:2018-01-01 01:12:13 ,浏览量:0

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 
 3 
 4 /* According to earlier standards */
 5 #include 
 6 #include 
 7 #include 
 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集全部清除

 

简单的例子:

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

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
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 #include
  8 #include
  9 #include
 10 #include
 11 #include
 12 #include
 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 \n", __LINE__); \
 32      exit(-1); \
 33   }while(0);
 34 
 35 #define  Waring( inf ) \
 36 do{    \
 37      perror( inf );  \
 38      printf("it happened in %d \n", __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 \n", 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  \n", 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  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
 2 #include
 3 #include
 4 #include
 5 #include
 6 #include
 7 #include
 8 #include
 9 #include
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 \n",__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 !\n");
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.   

     

编程是一种快乐,享受代码带给我的乐趣!!!
关注
打赏
1659628745
查看更多评论
立即登录/注册

微信扫码登录

0.0464s