linux 网络编程---->多路复用:select实例—转

//!> server端代码
//!>server.c

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 #include <errno.h>
  6 #include <netinet/in.h>
  7 #include <sys/select.h>
  8 #include <sys/types.h>
  9 #include <sys/socket.h>
 10 
 11 #define BUF_LEN 1024
 12 #define SERV_PORT 6000
 13 #define FD_SIZE 100
 14 #define MAX_BACK 100
 15 
 16 int main( int argc, char ** argv )
 17 {
 18   
 19    int          listenfd,connfd, sockfd, maxfd, maxi, i;
 20     int          nready,client[FD_SIZE];      //!> 接收select返回值、保存客户端套接字
 21     int          lens;
 22     ssize_t   n;            //!> read字节数
 23    fd_set       rset,allset;   //!> 不要理解成就只能保存一个,其实fd_set有点像封装的数组
 24     char      buf[BUF_LEN];            
 25    socklen_t   clilen;
 26     structsockaddr_in servaddr, chiaddr;
 27    
 28     if( (listenfd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
 29     {
 30        printf("Create socket Error : %d\n", errno );
 31        exit(EXIT_FAILURE );
 32     }
 33    
 34    //!>
 35    //!> 下面是接口信息
 36     bzero(&servaddr, sizeof( servaddr ) );
 37    servaddr.sin_family = AF_INET;
 38    servaddr.sin_addr.s_addr  =htonl( INADDR_ANY);
 39    servaddr.sin_port = htons( SERV_PORT );
 40    
 41    //!>
 42    //!> 绑定
 43     if( bind(listenfd, ( struct sockaddr * )&servaddr, sizeof(servaddr ) ) == -1 )
 44    {   
 45        printf("BindError : %d\n", errno);
 46       exit(EXIT_FAILURE  );
 47     }
 48    
 49    //!>
 50    //!> 监听
 51     if( listen(listenfd, MAX_BACK ) == -1 )
 52     {
 53       printf("Listen Error : %d\n", errno );
 54        exit(EXIT_FAILURE );
 55     }
 56    
 57    //!> 当前最大的感兴趣的套接字fd
 58     maxfd =listenfd;   //!> 当前可通知的最大的fd
 59     maxi =-1;         //!> 仅仅是为了client数组的好处理
 60    
 61     for( i = 0;i < FD_SIZE; i++)   //!> 首先置为全-1
 62     {
 63        client[i] =-1;      //!> 首先client的等待队列中是没有的,所以全部置为-1
 64     }
 65    
 66     FD_ZERO(&allset);      //!> 先将其置为0
 67     FD_SET(listenfd, &allset );
 68                //!> 说明当前我对此套接字有兴趣,下次select的时候通知我!
 69    
 70     while( 1)
 71     {
 72        rset =allset;//!> 由于allset可能每次一个循环之后都有变化,所以每次都赋值一次
 73        if( (nready= select( maxfd + 1, &rset, NULL, NULL, NULL )) ==-1)
 74       {               //!> if 存在关注
 75          printf("Select Erorr : %d\n", errno );
 76           exit(EXIT_FAILURE );
 77        }
 78       
 79        if( nready<= 0)         //!> if 所有的感兴趣的没有就接着回去select
 80        {
 81          continue;
 82        }
 83       
 84       
 85       
 86        if(FD_ISSET( listenfd, &rset ))         //!> if 是监听接口上的“来电”
 87       {                                 //!>
 88          //!> printf("server listen ...\n");
 89           clilen =sizeof( chiaddr );
 90          
 91          printf("Start doing... \n");
 92          
 93             if( (connfd  = accept( listenfd, (struct sockaddr*)&chiaddr, &clilen ) ) == -1)
 94            {                              //!> accept 返回的还是套接字
 95                printf("Accept Error : %d\n", errno );
 96               continue;
 97             }
 98            
 99            
100             for( i = 0;i < FD_SIZE; i++)   //!> 注意此处必须是循环,刚开始我认
101                                       //!> 为可以直接设置一个end_i来直接处
102                                       //!> 理,实质是不可以的!因为每个套接
103            {                           //!> 字的退出时间是不一样的,后面的
104                if(client[i] < 0)            //!> 可能先退出,那么就乱了,所以只
105               {                        //!> 有这样了!
106                   client[i] =connfd;         //!> 将client的请求连接保存
107                   break;
108                }
109             }
110            
111             if( i ==FD_SIZE )            //!> The last one
112             {
113                printf( "Tomany ... " );
114                close(connfd );         //!> if 满了那么就不连接你了,关闭吧
115             continue;               //!> 返回
116             }
117                                  //!> listen的作用就是向数组中加入套接字!
118           FD_SET(connfd, &allset);   //!> 说明现在对于这个连接也是感兴趣的!
119                                  //!> 所以加入allset的阵容
120           if( connfd> maxfd)         //!> 这个还是为了解决乱七八糟的数组模型
121                                  //!> 的处理
122           {
123              maxfd =connfd;
124           }
125          
126           if( i> maxi)               //!> 同上
127           {
128              maxi =i;
129           }
130        }
131 
132       //!> 下面就是处理数据函数( 其实说本质的select还是串行 )
133        for( i = 0;i <= maxi; i++)      //!> 对所有的连接请求的处理
134        {
135           if( ( sockfd= client[i] ) > 0)   //!> 还是为了不规整的数组
136          {         //!> 也就说client数组不是连续的全正数或者-1,可能是锯齿状的
137              if(FD_ISSET( sockfd, &rset ))   //!> if 当前这个数据套接字有要读的
138               {
139                  memset( buf,0, sizeof( buf ));   //!> 此步重要,不要有时候出错
140              
141                  n = read(sockfd, buf, BUF_LEN);
142                  if( n< 0 )
143                  {
144                    printf("Error!\n");
145                     close(sockfd );         //!> 说明在这个请求端口上出错了!
146                    FD_CLR(sockfd, &allset );
147                    client[i] =-1;
148                   continue;
149                  }
150                 if( n == 0)
151                 {
152                    printf("nodata\n");
153                    close(sockfd );         //!> 说明在这个请求端口上读完了!
154                    FD_CLR(sockfd, &allset );
155                    client[i] =-1;
156                   continue;
157                 }
158                
159                printf("Server Recv: %s\n", buf);
160                
161                 if( strcmp(buf, "q" ) == 0)            //!> 客户端输入“q”退出标志
162                 {
163                    close(sockfd );
164                    FD_CLR(sockfd, &allset );
165                    client[i] =-1;
166                   continue;
167                 }
168                
169                printf("Server send : %s\n", buf);
170                 write(sockfd, buf, n);      //!> 读出来的写进去
171              }
172           }
173        }
174       
175     }
176    
177     return0;
178 }

 

//!> client端代码
//!>client.c

 

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 #include <errno.h>
  6 #include <netinet/in.h>
  7 #include <sys/types.h>
  8 #include <sys/socket.h>
  9 #include <arpa/inet.h>
 10 #include <sys/select.h>
 11 
 12 #define MAXLINE 1024
 13 #define SERV_PORT 6000
 14 
 15 //!> 注意输入是由stdin,接受是由server发送过来
 16 //!> 所以在client端也是需要select进行处理的
 17 void send_and_recv( int connfd )
 18 {
 19     FILE * fp =stdin;
 20    int   lens;
 21     charsend[MAXLINE];
 22     charrecv[MAXLINE];
 23     fd_setrset;
 24     FD_ZERO(&rset );
 25     int maxfd =( fileno( fp ) > connfd ? fileno( fp ) :connfd  + 1);   
 26                                     //!> 输入和输出的最大值
 27     int n;
 28    
 29     while( 1)
 30     {
 31        FD_SET(fileno( fp ), &rset );
 32        FD_SET(connfd, &rset);         //!> 注意不要把rset看作是简单的一个变量
 33                                     //!> 注意它其实是可以包含一组套接字的哦,
 34                                     //!> 相当于是封装的数组!每次都要是新的哦!
 35       
 36        if( select(maxfd, &rset, NULL, NULL, NULL ) == -1 )
 37        {
 38          printf("Client Select Error..\n");
 39          exit(EXIT_FAILURE  );
 40        }
 41       
 42       //!> if 连接口有信息
 43        if(FD_ISSET( connfd, &rset ))   //!> if 连接端口有信息
 44        {
 45           printf("client get from server ...\n" );
 46           memset(recv, 0, sizeof( recv ) );
 47           n = read(connfd, recv, MAXLINE );
 48           if( n == 0)
 49           {
 50              printf("Recvok...\n");
 51              break;
 52           }
 53           else if( n== -1 )
 54           {
 55              printf("Recverror...\n");
 56              break;
 57           }
 58           else
 59           {
 60              lens =strlen( recv );
 61              recv[lens] ='\0';
 62             //!> 写到stdout
 63              write(STDOUT_FILENO, recv, MAXLINE );
 64             printf("\n");
 65           }
 66 
 67        }
 68       
 69       //!> if 有stdin输入
 70        if(FD_ISSET( fileno( fp ), &rset ))   //!> if 有输入
 71        {
 72          //!> printf("client stdin ...\n");
 73          
 74           memset(send, 0, sizeof( send ) );
 75           if( fgets(send, MAXLINE, fp ) == NULL )
 76           {
 77             printf("End...\n");
 78              exit(EXIT_FAILURE );
 79           }
 80           else
 81           {
 82             //!>if( str )
 83              lens =strlen( send );
 84              send[lens-1]= '\0';      //!> 减一的原因是不要回车字符
 85                                  //!> 经验值:这一步非常重要的哦!!!!!!!!
 86              if( strcmp(send, "q" ) == 0 )
 87              {
 88                 printf("Bye..\n" );
 89                return;
 90              }
 91             
 92             printf("Client send : %s\n", send);
 93              write(connfd, send, strlen( send ) );
 94           }
 95        }
 96       
 97     }
 98    
 99 }
100 
101 int main( int argc, char ** argv )
102 {
103    //!> char * SERV_IP = "10.30.97.188";
104     char   buf[MAXLINE];
105    int     connfd;
106     structsockaddr_in servaddr;
107    
108     if( argc !=2 )
109     {
110       printf("Input server ip !\n");
111        exit(EXIT_FAILURE );
112     }
113    
114    //!> 建立套接字
115     if( ( connfd= socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
116     {
117       printf("Socket Error...\n" , errno );
118        exit(EXIT_FAILURE );
119     }
120 
121    //!> 套接字信息
122    bzero(&servaddr, sizeof(servaddr));
123    servaddr.sin_family = AF_INET;
124    servaddr.sin_port = htons(SERV_PORT);
125    inet_pton(AF_INET, argv[1],&servaddr.sin_addr);
126    
127    //!> 链接server
128     if( connect(connfd, ( struct sockaddr * )&servaddr, sizeof( servaddr ) ) < 0)
129     {
130       printf("Connect error..\n");
131       exit(EXIT_FAILURE);
132    }   
133    
134 
135    //!>
136    //!> send and recv
137    send_and_recv( connfd );
138    
139    //!>
140 
141     close(connfd );
142    printf("Exit\n");
143    
144     return0;
145 }

 

编译+运行:

gcc -o server server.c
gcc -o client   client.c

./server
./client10.80.1.251    (注意参数你指定的server的IP哦  )


如果要多个一起运行,给个脚本:

 1 #!/bin/sh
 2 index=10
 3 
 4 while [ $index -gt 0 ]
 5 do
 6     ./client  10.80.1.251&         # 注意在后台哦,所以只能看到在server下的现象,可以自己改进
 7      $index = `expr $index - 1`
 8 done
 9 
10 exit 0

 

 

 

posted @ 2012-07-27 15:28  戊辰岁终  阅读(331)  评论(0编辑  收藏  举报