linux 网络编程---->多路复用:select实例! 分手后的思念是犯贱 2022-06-13 03:12 148阅读 0赞 **好吧,我承认找了好久,网上都没有像样的完整的实例,然后自己参照书自己写一个吧!** **//!> server端代码** **//!>server.c** \#include <stdio.h> \#include <unistd.h> \#include <stdlib.h> \#include <string.h> \#include <errno.h> \#include <netinet/in.h> \#include <sys/select.h> \#include <sys/types.h> \#include <sys/socket.h> \#define BUF\_LEN 1024 \#define SERV\_PORT 6000 \#define FD\_SIZE 100 \#define MAX\_BACK 100 int main( int argc, char \*\* argv ) \{ int listenfd,connfd, sockfd, maxfd, maxi, i; int nready,client\[FD\_SIZE\]; //!> 接收select返回值、保存客户端套接字 int lens; ssize\_t n; //!> read字节数 fd\_set rset,allset; //!> 不要理解成就只能保存一个,其实fd\_set有点像封装的数组 char buf\[BUF\_LEN\]; socklen\_t clilen; structsockaddr\_in servaddr, chiaddr; if( (listenfd = socket( AF\_INET, SOCK\_STREAM, 0 ) ) == -1 ) \{ printf("Create socket Error : %d\\n", errno ); exit(EXIT\_FAILURE ); \} //!> //!> 下面是接口信息 bzero(&servaddr, sizeof( servaddr ) ); servaddr.sin\_family = AF\_INET; servaddr.sin\_addr.s\_addr =htonl( INADDR\_ANY); servaddr.sin\_port = htons( SERV\_PORT ); //!> //!> 绑定 if( bind(listenfd, ( struct sockaddr \* )&servaddr, sizeof(servaddr ) ) == -1 ) \{ printf("BindError : %d\\n", errno); exit(EXIT\_FAILURE ); \} //!> //!> 监听 if( listen(listenfd, MAX\_BACK ) == -1 ) \{ printf("Listen Error : %d\\n", errno ); exit(EXIT\_FAILURE ); \} //!> 当前最大的感兴趣的套接字fd maxfd =listenfd; //!> 当前可通知的最大的fd maxi =-1; //!> 仅仅是为了client数组的好处理 for( i = 0;i < FD\_SIZE; i++) //!> 首先置为全-1 \{ client\[i\] =-1; //!> 首先client的等待队列中是没有的,所以全部置为-1 \} FD\_ZERO(&allset); //!> 先将其置为0 FD\_SET(listenfd, &allset ); //!> 说明当前我对此套接字有兴趣,下次select的时候通知我! while( 1) \{ rset =allset;//!> 由于allset可能每次一个循环之后都有变化,所以每次都赋值一次 if( (nready= select( maxfd + 1, &rset, NULL, NULL, NULL )) ==-1) \{ //!> if 存在关注 printf("Select Erorr : %d\\n", errno ); exit(EXIT\_FAILURE ); \} if( nready<= 0) //!> if 所有的感兴趣的没有就接着回去select \{ continue; \} if(FD\_ISSET( listenfd, &rset )) //!> if 是监听接口上的“来电” \{ //!> //!> printf("server listen ...\\n"); clilen =sizeof( chiaddr ); printf("Start doing... \\n"); if( (connfd = accept( listenfd, (struct sockaddr\*)&chiaddr, &clilen ) ) == -1) \{ //!> accept 返回的还是套接字 printf("Accept Error : %d\\n", errno ); continue; \} for( i = 0;i < FD\_SIZE; i++) //!> 注意此处必须是循环,刚开始我认 //!> 为可以直接设置一个end\_i来直接处 //!> 理,实质是不可以的!因为每个套接 \{ //!> 字的退出时间是不一样的,后面的 if(client\[i\] < 0) //!> 可能先退出,那么就乱了,所以只 \{ //!> 有这样了! client\[i\] =connfd; //!> 将client的请求连接保存 break; \} \} if( i ==FD\_SIZE ) //!> The last one \{ printf( "Tomany ... " ); close(connfd ); //!> if 满了那么就不连接你了,关闭吧 continue; //!> 返回 \} //!> listen的作用就是向数组中加入套接字! FD\_SET(connfd, &allset); //!> 说明现在对于这个连接也是感兴趣的! //!> 所以加入allset的阵容 if( connfd> maxfd) //!> 这个还是为了解决乱七八糟的数组模型 //!> 的处理 \{ maxfd =connfd; \} if( i> maxi) //!> 同上 \{ maxi =i; \} \} //!> 下面就是处理数据函数( 其实说本质的select还是串行 ) for( i = 0;i <= maxi; i++) //!> 对所有的连接请求的处理 \{ if( ( sockfd= client\[i\] ) > 0) //!> 还是为了不规整的数组 \{ //!> 也就说client数组不是连续的全正数或者-1,可能是锯齿状的 if(FD\_ISSET( sockfd, &rset )) //!> if 当前这个数据套接字有要读的 \{ memset( buf,0, sizeof( buf )); //!> 此步重要,不要有时候出错 n = read(sockfd, buf, BUF\_LEN); if( n< 0 ) \{ printf("Error!\\n"); close(sockfd ); //!> 说明在这个请求端口上出错了! FD\_CLR(sockfd, &allset ); client\[i\] =-1; continue; \} if( n == 0) \{ printf("nodata\\n"); close(sockfd ); //!> 说明在这个请求端口上读完了! FD\_CLR(sockfd, &allset ); client\[i\] =-1; continue; \} printf("Server Recv: %s\\n", buf); if( strcmp(buf, "q" ) == 0) //!> 客户端输入“q”退出标志 \{ close(sockfd ); FD\_CLR(sockfd, &allset ); client\[i\] =-1; continue; \} printf("Server send : %s\\n", buf); write(sockfd, buf, n); //!> 读出来的写进去 \} \} \} \} return0; \} **//!> client端代码** **//!>client.c** \#include <stdio.h> \#include <unistd.h> \#include <stdlib.h> \#include <string.h> \#include <errno.h> \#include <netinet/in.h> \#include <sys/types.h> \#include <sys/socket.h> \#include <arpa/inet.h> \#include <sys/select.h> \#define MAXLINE 1024 \#define SERV\_PORT 6000 //!> 注意输入是由stdin,接受是由server发送过来 //!> 所以在client端也是需要select进行处理的 void send\_and\_recv( int connfd ) \{ FILE \* fp =stdin; int lens; charsend\[MAXLINE\]; charrecv\[MAXLINE\]; fd\_setrset; FD\_ZERO(&rset ); int maxfd =( fileno( fp ) > connfd ? fileno( fp ) :connfd \+ 1); //!> 输入和输出的最大值 int n; while( 1) \{ FD\_SET(fileno( fp ), &rset ); FD\_SET(connfd, &rset); //!> 注意不要把rset看作是简单的一个变量 //!> 注意它其实是可以包含一组套接字的哦, //!> 相当于是封装的数组!每次都要是新的哦! if( select(maxfd, &rset, NULL, NULL, NULL ) == -1 ) \{ printf("Client Select Error..\\n"); exit(EXIT\_FAILURE ); \} //!> if 连接口有信息 if(FD\_ISSET( connfd, &rset )) //!> if 连接端口有信息 \{ printf("client get from server ...\\n" ); memset(recv, 0, sizeof( recv ) ); n = read(connfd, recv, MAXLINE ); if( n == 0) \{ printf("Recvok...\\n"); break; \} else if( n== -1 ) \{ printf("Recverror...\\n"); break; \} else \{ lens =strlen( recv ); recv\[lens\] ='\\0'; //!> 写到stdout write(STDOUT\_FILENO, recv, MAXLINE ); printf("\\n"); \} \} //!> if 有stdin输入 if(FD\_ISSET( fileno( fp ), &rset )) //!> if 有输入 \{ //!> printf("client stdin ...\\n"); memset(send, 0, sizeof( send ) ); if( fgets(send, MAXLINE, fp ) == NULL ) \{ printf("End...\\n"); exit(EXIT\_FAILURE ); \} else \{ //!>if( str ) lens =strlen( send ); send\[lens-1\]= '\\0'; //!> 减一的原因是不要回车字符 //!> 经验值:这一步非常重要的哦!!!!!!!! if( strcmp(send, "q" ) == 0 ) \{ printf("Bye..\\n" ); return; \} printf("Client send : %s\\n", send); write(connfd, send, strlen( send ) ); \} \} \} \} int main( int argc, char \*\* argv ) \{ //!> char \* SERV\_IP = "10.30.97.188"; char buf\[MAXLINE\]; int connfd; structsockaddr\_in servaddr; if( argc !=2 ) \{ printf("Input server ip !\\n"); exit(EXIT\_FAILURE ); \} //!> 建立套接字 if( ( connfd= socket( AF\_INET, SOCK\_STREAM, 0 ) ) == -1 ) \{ printf("Socket Error...\\n" , errno ); exit(EXIT\_FAILURE ); \} //!> 套接字信息 bzero(&servaddr, sizeof(servaddr)); servaddr.sin\_family = AF\_INET; servaddr.sin\_port = htons(SERV\_PORT); inet\_pton(AF\_INET, argv\[1\],&servaddr.sin\_addr); //!> 链接server if( connect(connfd, ( struct sockaddr \* )&servaddr, sizeof( servaddr ) ) < 0) \{ printf("Connect error..\\n"); exit(EXIT\_FAILURE); \} //!> //!> send and recv send\_and\_recv( connfd ); //!> close(connfd ); printf("Exit\\n"); return0; \} 编译+运行: gcc -o server server.c gcc -o client client.c ./server ./client10.80.1.251 (注意参数你指定的server的IP哦 ) 如果要多个一起运行,给个脚本: \#!/bin/sh index=10 while \[ $index -gt 0 \] do ./client 10.80.1.251& \# 注意在后台哦,所以只能看到在server下的现象,可以自己改进 $index = \`expr $index - 1\` done exit 0
还没有评论,来说两句吧...