I/O多路转接之select——基于TCP协议
2016-05-28 14:23
567 查看
关于select的基础知识
a. select是系统提供的多路复用输入输出模型。它是用来监视多个文件句柄的状态变化。
b. 程序会停在select等,直到被监视的文件句柄至少有一个发生了状态改变。
c. 文件句柄是整数。例如:我们最熟悉的句柄是0、1、2,0是标准输入,1是标准输出,2是标准错误输出。0、1、2对应的FILE *结构的表示是stdin、stdout、stderr。
2. 函数
(1)select()
a. 参数
nfds:需要监视的最大文件描述符值加1;
readfds:select监视的可读文件句柄集合。
writefds: select监视的可写文件句柄集合。
exceptfds:select监视的异常文件句柄集合。
timeout:是struct timeval结构用于描述一段时间长度。用来设置select()的等待时间,其结构定义如下:
如果参数timeout设为:
NULL:select将一直被阻塞,直到某个文件描述符上发生了事件。
0:select将以非阻塞方式等,即检测描述符集的状态后立即返回,并不等待外部事件的发生。
大于0的值:
如果在指定的时间段里没有事件发生,select将超时返回0。
当readfds或writefds中映象的文件可读或可写或超时,本次select()结束返回。程序员利用一组系统提供的宏在select()结束时便可判断哪一文件可读或可写。
(见/usr/sys/select.h,可精确至百万分之一秒!)★除第一个外,所有参数既是输入型参数又是输出型参数。
b.返回值成功则返回文件描述词状态已改变的数目;
有错误返回-1;
超过timeout时间,返回0。
(2)几行相关的宏解释如下:
3.代码实现
修正版:
a. select是系统提供的多路复用输入输出模型。它是用来监视多个文件句柄的状态变化。
b. 程序会停在select等,直到被监视的文件句柄至少有一个发生了状态改变。
c. 文件句柄是整数。例如:我们最熟悉的句柄是0、1、2,0是标准输入,1是标准输出,2是标准错误输出。0、1、2对应的FILE *结构的表示是stdin、stdout、stderr。
2. 函数
(1)select()
a. 参数
nfds:需要监视的最大文件描述符值加1;
readfds:select监视的可读文件句柄集合。
writefds: select监视的可写文件句柄集合。
exceptfds:select监视的异常文件句柄集合。
timeout:是struct timeval结构用于描述一段时间长度。用来设置select()的等待时间,其结构定义如下:
如果参数timeout设为:
NULL:select将一直被阻塞,直到某个文件描述符上发生了事件。
0:select将以非阻塞方式等,即检测描述符集的状态后立即返回,并不等待外部事件的发生。
大于0的值:
如果在指定的时间段里没有事件发生,select将超时返回0。
当readfds或writefds中映象的文件可读或可写或超时,本次select()结束返回。程序员利用一组系统提供的宏在select()结束时便可判断哪一文件可读或可写。
(见/usr/sys/select.h,可精确至百万分之一秒!)★除第一个外,所有参数既是输入型参数又是输出型参数。
b.返回值成功则返回文件描述词状态已改变的数目;
有错误返回-1;
超过timeout时间,返回0。
(2)几行相关的宏解释如下:
void FD_CLR(int fd, fd_set *set); //清除文件句柄fd与set的联系。 int FD_ISSET(int fd, fd_set *set); //检查set联系的文件句柄fd是否可读写,当>0表示可读写。 void FD_SET(int fd, fd_set *set); //建立文件句柄fd与set的联系。 void FD_ZERO(fd_set *set); //清空set与所有文件句柄的联系。(关于fd_set及相关宏的定义见/usr/include/sys/types.h)
3.代码实现
//select_server.c 1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<assert.h> 4 #include<sys/select.h> 5 #include<sys/types.h> 6 #include<sys/socket.h> 7 #include<arpa/inet.h> 8 #include<netinet/in.h> 9 10 #define _BACKLOG_ 5 11 //将待处理的文件句柄保存放到select监控集中的fd 12 int fds[64]; 13 14 static void usage(const char* proc) 15 { 16 printf("usage:%s [ip] [port]\n",proc); 17 } 18 static int startup(char* ip,int port) 19 { 20 assert(ip); 21 //创建socket 22 int sock=socket(AF_INET,SOCK_STREAM,0); 23 if(sock<0) 24 { 25 perror("socket"); 26 exit(1); 27 } 28 28 //设置本地server端网络地址信息 29 struct sockaddr_in local; 30 local.sin_family=AF_INET; 31 local.sin_port=htons(port); 32 local.sin_addr.s_addr=inet_addr(ip); 33 //绑定 34 if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0) 35 { 36 perror("bind"); 37 exit(2); 38 } 39 //监听 40 if(listen(sock,_BACKLOG_)<0) 41 { 42 perror("listen"); 43 exit(3); 44 } 45 return sock; 46 } 47 int main(int argc,char*argv[]) 48 { 49 if(argc!=3) 50 { 51 usage(argv[0]); 52 exit(1); 53 } 54 55 char* ip=argv[1]; 56 int port=atoi(argv[2]); 57 //获取socket 58 int listen_sock=startup(ip,port); 59 60 int done=0; 61 int new_sock=-1; 62 struct sockaddr_in client;//创建网络地址信息结构体用于保存对端信息 63 socklen_t len=sizeof(client); 64 65 int max_fd;//最大文件描述符 66 fd_set _reads;//可读文件句柄集合 67 fd_set _writes;//可写文件句柄集合 68 69 int i=0; 70 int fds_num=sizeof(fds)/sizeof(fds[0]); 71 for(;i<fds_num;++i)//初始化发fds 72 { 73 fds[i]=-1; 74 } 75 fds[0]=listen_sock;//将fds的第一个元素设为监听套接字 76 max_fd=fds[0];//最大文件描述符设为fds第一个元素 77 78 while(!done) 79 { 80 FD_ZERO(&_reads);//清空_reads与所有文件句柄的联系。 81 FD_ZERO(&_writes);//清空_writes与所有文件句柄的联系。 82 FD_SET(listen_sock,&_reads);建立文件句柄lisen_sock与_reads的联系 83 struct timeval _timeout={5,0};//设定超时时间 84 for(i=1;i<fds_num;++i)//循环fds(加fd,取maxfd) 85 { 86 if(fds[i]>0) 87 { 88 FD_SET(fds[i],&_reads); 89 if(fds[i]>max_fd) 90 { 91 max_fd=fds[i]; 92 } 93 } 94 } 95 switch(select(max_fd+1,&_reads,&_writes,NULL,NULL)) 96 { 97 case 0: 98 //超时 99 printf("timeout\n"); 100 break; 101 case -1://出错 102 perror("select"); 103 break; 104 default://至少有一个IO事件已经就绪 105 { 106 i=0; 107 for(;i<fds_num;++i) 108 { 109 if(fds[i]==listen_sock&&FD_ISSET(fds[i],&_reads)) 110 { 111 //listen socket is ready! 112 new_sock=accept(listen_sock,(struct sockaddr*)&client,&len); 113 if(new_sock<0) 114 { 115 perror("accept"); 116 continue; 117 } 118 printf("get a new connect...%d\n",new_sock); 119 for(i=0;i<fds_num;++i)//将新的连接请求加入到fds 120 { 121 if(fds[i]==-1) 122 { 123 fds[i]=new_sock; 124 break; 125 } 126 } 127 if(i==fds_num)//如果i等于fds数组的大小,关掉new_sock 128 { 129 close(new_sock); 130 } 131 } 132 //别的文件句柄 133 else if(fds[i]>0 && FD_ISSET(fds[i],&_reads)) 134 { 135 char buf[1024]; 136 ssize_t _s=read(fds[i],buf,sizeof(buf)-1); 137 if(_s>0) 138 { 139 //read sucess 140 buf[_s]='\0'; 141 printf("client:%s\n",buf); 142 } 143 else if(_s==0) 144 { 145 //client shutdown 146 printf("client shutdown...\n"); 147 close(fds[i]); 148 fds[i]=-1; 149 } 150 else 151 { 152 perror("read"); 153 } 154 } 155 //normal socket 156 else 157 {} 158 } 159 } 160 break; 161 } 162 } 163 return 0; 164 } //select_client.c 1 #include<stdio.h> 2 #include<string.h> 3 #include<sys/select.h> 4 int main() 5 { 6 int std_in=0; 7 8 int max_fd=std_in; 9 struct timeval _timeout={5,0}; 10 11 fd_set _reads; 12 13 FD_ZERO(&_reads); 14 FD_SET(std_in,&_reads); 15 16 int done=0; 17 while(!done) 18 { 19 //set timeout 20 _timeout.tv_sec=5; 21 _timeout.tv_usec=0; 22 23 switch(select(max_fd+1,&_reads,NULL,NULL,&_timeout)) 24 { 25 case -1: 26 //error 27 perror("select"); 28 break; 29 case 0: 30 printf("select timeout...\n"); 31 break; 32 default: 33 { 34 if(FD_ISSET(std_in,&_reads)) 35 { 36 //read event ready 37 char buf[1024]; 38 memset(buf,'\0',sizeof(buf)); 39 ssize_t _s = read(std_in,buf,sizeof(buf)-1); 40 if(_s>0) 41 { 42 buf[_s]='\0'; 43 if(strncmp(buf,"quit",4)==0) 44 { 45 done=1; 46 continue; 47 } 48 printf("echo:%s\n",buf); 49 } 50 } 51 } 52 break; 53 } 54 } 55 return 0; 56 } //makefile 1 .PHONY:all 2 all:select_server select_client 3 select_server:select_server.c 4 gcc -o $@ $^ 5 select_client:select_client.c 6 gcc -o $@ $^ 7 .PHONY:clean 8 clean: 9 rm -f select_server select_client //start.sh 1 #!/bin/bash 2 3 service iptables stop 4 ./select_server 192.168.163.128 8080输出结果:
修正版:
//select_client.c 1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<sys/select.h> 5 #include<sys/socket.h> 6 #include<netinet/in.h> 7 #include<unistd.h> 8 9 void usage(const char* proc) 10 { 11 printf("%s [ip] [port]\n",proc); 12 exit(1); 13 } 14 int main(int argc,char* argv[]) 15 { 16 if(argc!=3) 17 { 18 usage(argv[0]); 19 exit(1); 20 } 21 int server_ip=inet_addr(argv[1]); 22 int server_port=atoi(argv[2]); 23 24 int client_sock=socket(AF_INET,SOCK_STREAM,0); 25 if(client_sock<0) 26 { 27 perror("socket"); 28 exit(2); 29 } 30 struct sockaddr_in server; 31 server.sin_family=AF_INET; 32 server.sin_addr.s_addr=server_ip; 33 server.sin_port=htons(server_port); 34 35 if(connect(client_sock,(struct sockaddr*)&server,sizeof(server))<0) 36 { 37 perror("connect"); 38 exit(3); 39 } 40 char buf[1024]; 41 while(1) 42 { 43 memset(buf,'\0',sizeof(buf)); 44 printf("Please Input: "); 45 fflush(stdout); 46 fgets(buf,sizeof(buf)-1,stdin); 47 if(send(client_sock,buf,sizeof(buf)-1,0)<0) 48 { 49 perror("send"); 50 continue; 51 } 52 ssize_t _size=recv(client_sock,buf,sizeof(buf)-1,0); 53 if(_size>0) 54 { 55 buf[_size]='\0'; 56 printf("server receive:%s\n",buf); 57 } 58 } 59 return 0; 60 } //select_server.c 1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<assert.h> 4 #include<sys/select.h> 5 #include<sys/types.h> 6 #include<sys/socket.h> 7 #include<arpa/inet.h> 8 #include<netinet/in.h> 9 10 #define _BACKLOG_ 5 11 12 int fds[64]; 13 14 static void usage(const char* proc) 15 { 16 printf("usage:%s [ip] [port]\n",proc); 17 } 18 static int startup(char* ip,int port) 19 { 20 assert(ip); 21 // 22 int sock=socket(AF_INET,SOCK_STREAM,0); 23 if(sock<0) 24 { 25 perror("socket"); 26 exit(1); 27 } 28 // 29 struct sockaddr_in local; 30 local.sin_family=AF_INET; 31 local.sin_port=htons(port); 32 local.sin_addr.s_addr=inet_addr(ip); 33 // 34 if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0) 35 { 36 perror("bind"); 37 exit(2); 38 } 39 // 40 if(listen(sock,_BACKLOG_)<0) 41 { 42 perror("listen"); 43 exit(3); 44 } 45 return sock; 46 } 47 int main(int argc,char*argv[]) 48 { 49 if(argc!=3) 50 { 51 usage(argv[0]); 52 exit(1); 53 } 54 55 char* ip=argv[1]; 56 int port=atoi(argv[2]); 57 58 int listen_sock=startup(ip,port); 59 60 int done=0; 61 int new_sock=-1; 62 struct sockaddr_in client; 63 socklen_t len=sizeof(client); 64 65 int max_fd; 66 fd_set _reads; 67 fd_set _writes; 68 69 int i=0; 70 int fds_num=sizeof(fds)/sizeof(fds[0]); 71 for(;i<fds_num;++i) 72 { 73 fds[i]=-1; 74 } 75 fds[0]=listen_sock; 76 max_fd=fds[0]; 77 78 while(!done) 79 { 80 FD_ZERO(&_reads); 81 FD_ZERO(&_writes); 82 FD_SET(listen_sock,&_reads); 83 struct timeval _timeout={5,0}; 84 for(i=1;i<fds_num;++i) 85 { 86 if(fds[i]>0) 87 { 88 FD_SET(fds[i],&_reads); 89 FD_SET(fds[i],&_writes); 90 if(fds[i]>max_fd) 91 { 92 max_fd=fds[i]; 93 } 94 } 95 } 96 switch(select(max_fd+1,&_reads,&_writes,NULL,&_timeout)) 97 { 98 case 0: 99 //timeout 100 printf("timeout...\n"); 101 break; 102 case -1: 103 perror("select"); 104 break; 105 default: 106 { 107 i=0; 108 for(;i<fds_num;++i) 109 { 110 if(fds[i]==listen_sock&&FD_ISSET(fds[i],&_reads)) 111 { 112 //listen socket is ready! 113 new_sock=accept(listen_sock,(struct sockaddr*)&client,&len); 114 if(new_sock<0) 115 { 116 perror("accept"); 117 continue; 118 } 119 char* client_ip=inet_ntoa(client.sin_addr); 120 int client_port=ntohs(client.sin_port); 121 printf("get a new connect...[ip]:%s [port]:%d\n",client_ip,client_port); 122 for(i=0;i<fds_num;++i) 123 { 124 if(fds[i]==-1) 125 { 126 fds[i]=new_sock; 127 break; 128 } 129 } 130 if(i==fds_num) 131 { 132 close(new_sock); 133 } 134 } 135 //listen socket 136 else if(fds[i]>0 && FD_ISSET(fds[i],&_reads)) 137 { 138 char buf[1024]; 139 ssize_t _s=read(fds[i],buf,sizeof(buf)-1); 140 if(_s>0) 141 { 142 //read sucess 143 buf[_s]='\0'; 144 printf("client:%s",buf); 145 if(FD_ISSET(fds[i],&_writes)); 146 { 147 _s=write(fds[i],buf,sizeof(buf)-1); 148 if(_s>0) 149 { 150 //write sucess 151 // buf[_s]='\0'; 152 // printf("server:%s\n",buf); 153 } 154 else if(_s<0) 155 { 156 perror("write"); 157 exit(1); 158 } 159 else 160 { 161 printf("can not write back...\n"); 162 } 163 } 164 } 165 else if(_s==0) 166 { 167 //client shutdown 168 printf("client shutdown...\n"); 169 close(fds[i]); 170 fds[i]=-1; 171 } 172 else 173 { 174 perror("read"); 175 } 176 } 177 //normal socket 178 else 179 {} 180 } 181 } 182 break; 183 } 184 } 185 return 0; 186 }输出结果:
相关文章推荐
- Lua编程示例(一):select、debug、可变参数、table操作、error
- Lua中的文件I/O操作教程
- SQL学习笔记三 select语句的各种形式小结
- 一条select语句引起的瓶颈问题思考
- SQL Select语句完整的执行顺序
- mysql SELECT语句去除某个字段的重复信息
- 点击按钮后 文本框变为Select下拉列表框
- javascript 模拟select下拉列表特效
- javascript select options 排序(保持option 对象完整性)
- 用javascript和css模拟select的脚本
- js select常用操作控制代码
- mysql中insert与select的嵌套使用方法
- jquery的clone方法应用于textarea和select的bug修复
- TCP版backshell的VBS脚本代码
- SQLServer中SELECT语句的执行顺序
- MySQL进阶SELECT语法篇
- asp中 select top 问题!~
- ASP中获得Select Count语句返回值的方法
- 探讨select in 在postgresql的效率问题
- 数据库插入数据之select into from与insert into select区别详解