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

浙公网安备 33010602011771号