高级I/O之多路转接select
来源:互联网 发布:用centos开发安卓软件 编辑:程序博客网 时间:2024/05/16 12:28
一.关于I/O
要提高网络服务服务器,提高I/O性能,本质上是在提高“等”的比重,“等”的比重趋于零,性能越好,而I/O中为了减少等的比重,可以让I/O一次等多个文件描述符,即I/O模型中的多路复用模型,本文则讨论的是多路复用之select模型
二.select函数
1.select函数的作用
系统提供select函数来实现多路复用输入/输出模型。select系统调用是用来让我们的程序监视多个文件句柄的状态变化。程序会在select那里以timeout的形式等待,直到被监视的文件句柄有一个或者多个发生了改变。(关于文件句柄其实就是一个整数,我们最熟悉的句柄是0,1,2三个0是标准输入流,1是标准输出流,2是标准错误输出。0,1,2对应的FILE*结构的表示就是stdin,stdout,stderr。)
2.select函数的参数
- 参数nfds就是需要监视的最大文件描述符值+1
- 参数rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集合和异常文件描述符的集合。
参数timeout为结构体timeval,用来设置select()的等待时
- timeout为NULL ,则表示select将一直被阻塞,直到某个文件描述符上发生了事件。
- 为0,则表示仅仅检测文件描述符集合的状态,然后立即返回,并不等待外部事件发生
- 为自己设定的特定的时间值,表示如果在自己指定的时间内没有事件发生,select将超时返回。
函数返回值
- 执行成功则返回 文件描述词状态已经改变的个数。
- 如果返回0则表示在文件描述词改变之前已经超过timeout的时间,没有返回。
- 返回-1则表示有错误发生。
三.自己实现myselect服务器
1.所用到的函数及宏
FD_CLR(int fd,fd _set* set)
:用来清除描述词组set中相关fd的位。FD_ISSET(int fd,fd _set* set)
:用来测试描述词组set的相关fd的位是否为真FD_SET(int fd,fd _set* set)
:用来设置描述词组set的相关fd的位FD_ZERO(fd _set* set)
:用来清除描述词组set的全部位
select服务器端(支持读和写)
#include<stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <unistd.h>#include<arpa/inet.h>#include<netinet/in.h>#include<string.h>int fds_array[sizeof(fd_set)*8];//用数组的元素来标记对应的位的文件描述符是否有事件发生 有则置1 static void* Usage(const char* proc){ printf("Usage:%s[local_ip][local_port]\n",proc);}int starup(const char* ip,int port){ int sock = socket(AF_INET,SOCK_STREAM,0); if(sock < 0) { perror("socket"); return 1; } struct sockaddr_in local; local.sin_family = AF_INET; local.sin_port = htons(port); local.sin_addr.s_addr = inet_addr(ip); int b=bind(sock,(struct sockaddr*)&local,sizeof(local)); if(b<0) { perror("bind"); return 2; } if(listen(sock,10)<0) { perror("listen"); return 3; } return sock;}int main(int argc, char* argv[]){ if(argc != 3) { Usage(argv[0]); return 4; } int listen_sock = starup(argv[1],atoi(argv[2])); fd_set rfds; fd_set wfds; FD_ZERO(&rfds); FD_ZERO(&wfds); int i=0; int num = sizeof(fds_array)/sizeof(fds_array[0]); for(; i<num; ++i)//给数组的所有标志位均置为-1 { fds_array[i] = -1; } fds_array[0] = listen_sock; while(1) { int maxfd = -1; for(i=0; i<num; i++) { if(fds_array[i]==-1) { continue; } FD_SET(fds_array[i],&rfds); FD_SET(fds_array[i],&wfds); if(maxfd<fds_array[i]) { maxfd = fds_array[i]; } } switch(select(maxfd+1,&rfds,&wfds,NULL,NULL)) { case 0: printf("timeout...\n"); break; case -1: perror("select"); break; default: { ///at least one read event ready for(i=0; i<num; i++) { struct sockaddr_in client; socklen_t len = sizeof(client); if(fds_array[i]<0) { continue; } if(i==0 && FD_ISSET(listen_sock,&rfds))//listen_sock文件描述符有事件发生 { int new_sock = accept(listen_sock,\ (struct sockaddr*)&client,&len); if(new_sock<0) { perror("accept"); continue; } printf("get a client [%s:%d]\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port)); int j=0; for(;j<num; j++) { if(fds_array[j]<0) { break; } } if(j==num) { printf("fd_set full\n"); close(new_sock); } else { fds_array[j] = new_sock; } } else if(i!=0 &&( FD_ISSET(fds_array[i],&rfds)||(FD_ISSET(fds_array[i],&wfds))))//普通文件描述符有事件发生 { char buf[1024]; if(FD_ISSET(fds_array[i],&rfds))//有读的事件发生 { // char buf[1024]; ssize_t s= read(fds_array[i],buf,sizeof(buf)-1); if(s>0) { buf[s]=0; printf("client#%s\n",buf); if(FD_ISSET(fds_array[i],&wfds))//有写的事件发生 { printf("please enter:"); fflush(stdout); ssize_t r = read(0,buf,sizeof(buf)-1); if(r>0) { buf[r] = 0; ssize_t w = write(fds_array[i],buf,strlen(buf)); if(w>0) { buf[w] = 0; printf("server echo:%s\n",buf); } else if(w==0) { printf("no data enter\n"); close(fds_array[i]); fds_array[i] = -1; } else { printf("server error\n"); close(fds_array[i]); fds_array[i] = -1; } } } } else if(s==0) { printf("client is quit\n"); close(fds_array[i]); fds_array[i] = -1; } else { printf("client error\n"); close(fds_array[i]); fds_array[i] = -1; } } } else{ } } } break; } }}
运行结果图:
服务器端:
客户端:
客户端(普通版本)
#include<stdio.h>#include<stdlib.h>#include<sys/socket.h>#include <netinet/in.h>#include<sys/types.h>#include<arpa/inet.h>#include<string.h>#include<fcntl.h>#include<unistd.h>static void* Usage(const char* proc){ printf("Usage:%s[local_ip][local_port]\n",proc);}int main(int argc,char* argv[]){ if(argc != 3) { Usage(argv[0]); return 1; } int sock = socket(AF_INET,SOCK_STREAM,0); if(sock < 0 ) { perror("socket"); exit(2); } struct sockaddr_in server_sock; server_sock.sin_family = AF_INET; server_sock.sin_port = htons(atoi(argv[2])); server_sock.sin_addr.s_addr = inet_addr(argv[1]); if(connect(sock,(struct sockaddr*)&server_sock,sizeof(server_sock))<0) { printf("connect failed "); exit(3); } printf("connect success\n"); char buf[1024]; while(1) { printf("Please Enter#"); fflush(stdout); ssize_t s=read(0,buf,sizeof(buf)-1); if(s>0) { buf[s-1]=0; write(sock,buf,strlen(buf)); ssize_t s = read(sock,buf,sizeof(buf)-1); if(s>0) { buf[s] = 0; printf("server ehco:%s\n ",buf); } } } return 0;}
结果图:
服务器端:
客户端
阅读全文
0 0
- 高级I/O之多路转接select
- 高级I/O之多路转接epoll
- 高级I/O之多路转接poll
- I/O的多路转接: select
- I/O多路转接----select调用
- I/O多路转接之select
- I/O多路转接之select
- I/O多路转接之select
- I/O多路转接之select
- I/O多路转接之select
- I/O多路转接之select
- 【Linux】I/O多路转接select
- I/O多路转接之select
- I/O多路转接之select
- I/O多路转接之--select
- I/O多路转接之select
- I/O多路转接----select
- I/O多路转接之select
- 用Python 生成 不同语言的MAVLink 开发库
- 没标题
- lpc1768
- js小知识
- C#185课的主要内容
- 高级I/O之多路转接select
- binder驱动代码注释下
- C++的PIMPL模式解析
- jquery中attr和prop的区别
- AwesomePlayer
- vsftp安装创建账号并限定使用文件夹
- JDBC常见面试题集锦
- 常见http状态码
- JavaScript判断变量是否是数组