select服务器
来源:互联网 发布:抢网速的软件 编辑:程序博客网 时间:2024/05/29 02:17
1.select简单介绍
①select:一次用来等待多个文件描述符,只负责等待
②select函数:
int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout)
③参数介绍:
- 第一个参数nfds表示最大的文件描述符+1
- fd_set是文件描述符集,readfds表示读事件,writefds表示写事件,exceptfds表示异常事件;
- 后四个参数都是输入输出型参数:中间三个参数在输入时,比特位的内容表示关心的文件描述符事件,输出时,比特位的内容表示哪个文件描述符已经就绪。
- 例如:在输入时,readfds的第3个比特位为1,表示只关心3号文件描述符的读事件;在输出时,readfds的第3个比特位为1,表示3号文件描述符已经就绪;
- 最后一个参数timeout可以将select设置为阻塞式等待、非阻塞式等待或按特定时间非阻塞等待;
④只要有任何一个事件就绪,select就会返回;
2.select服务器
①select服务器介绍
select()检测到来自服务器端的connect()行为,作为输入参数,readfds,writefds,exceptfds应该标记所有需要探测的“可读事件”,“可写事件”,“错误事件”的句柄,作为输出参数,readfds,writefds,exceptfds中保存了select()捕捉到所有事件的句柄值,使用FD_ISSET检查哪些句柄发生了事件。
②编写select服务器:
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<sys/select.h>#include<fcntl.h>int fds[1024];static void Usage(const char* proc){//服务器的使用介绍 printf("%s[local_ip][local_post]\n",proc);}int startup(const char* _ip,int _port){ //创建套接字 int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(2); } struct sockaddr_in local; local.sin_family=AF_INET; local.sin_port=htons(_port); local.sin_addr.s_addr=inet_addr(_ip); //绑定套接字 if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0) { perror("bind"); exit(3); } //监听套接字 if(listen(sock,10)) { perror("listen"); exit(4); } return sock;}int main(int argc,char* argv[]){ if(argc!=3) { Usage(argv[0]); return 1; } //创建监听套接字 int listen_sock=startup(argv[1],atoi(argv[2])); int nums=sizeof(fds)/sizeof(fds[0]); int maxfd=-1; int i=1; for(;i<nums;i++) { fds[i]=-1;//从1开始清空文件描述符 } //将listen_sock托管给select_server fds[0]=listen_sock; while(1) { struct timeval timeout={5,0}; fd_set rfds; //清空rfds的所有位 FD_ZERO(&rfds); maxfd=-1; for(i=0;i<nums;i++) { if(fds[i]>0) { //标记可读事件句柄,在rfds中设置文件描述符 FD_SET(fds[i],&rfds); if(maxfd<fds[i]) {//获取最大文件描述符 maxfd=fds[i]; } } } switch(select(maxfd+1,&rfds,NULL,NULL,/*&timeout*/NULL)) { case 0: printf("timeout...\n"); break; case -1: perror("select"); break; default: { for(i=0;i<nums;i++) { if(fds[i]<0) {//遍历rdfs continue; } if(i==0 && FD_ISSET(listen_sock,&rfds)) {//listen_sock就绪 struct sockaddr_in client; socklen_t len=sizeof(client); //等待客户端的连接 int new_sock=accept(listen_sock,(struct sockaddr*)&client,&len); if(new_sock<0) { perror("accept"); continue; } //客户端成功连接 printf("get new client:[%s:%d]\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port)); int j=1; for(;j<nums;j++) { if(fds[j]==-1) { break; } } if(j==nums) { printf("server full!\n"); close(new_sock); } else { fds[j]=new_sock; } } else if(i>0 && FD_ISSET(fds[i],&rfds)) {//其他事件就绪 char buf[1024]; //读取客户端发送的数据 ssize_t s=read(fds[i],buf,sizeof(buf)-1); if(s>0) { buf[s]=0; printf("client say# %s\n",buf); } else if(s==0) {//客户端断开连接 printf("client quit!\n"); close(fds[i]); fds[i]=-1; } else { perror("read"); } } else {} } } break; } }}
运行结果:
使用telnet连接select服务器,连接成功后给出提示,并且telnet向select发送数据:
当telent退出时,select给出连接断开的提示:
3.select的优缺点
优点:
与多线程和多进程服务器相比,select一次等待多个文件描述符,等待时间变短,提高了性能;
缺点:
①select本身对能监控的文件描述符有上限,默认为1024;
②每次使用select都要将后4个参数重新设置,性能变低;
③每次调用select都要遍历所有fd,当fd较多时,开销很大;
④select为系统调用,每次调用都要将fd集合从用户态拷贝到内核,开销很大;
阅读全文
0 0
- Select服务器
- select服务器
- select服务器
- select服务器
- select服务器
- select服务器
- select服务器
- select服务器
- select服务器
- select服务器
- select服务器
- select服务器
- Select服务器
- select服务器
- select多路单线程服务器
- select模型服务器代码
- python 服务器 select 游戏
- tcp服务器(使用select)
- synchronized 原理
- 关于tornado中模板的渲染
- C++ typedef
- Hbase compact以及split跟踪
- zoj 2100 dfs暴力宽搜
- select服务器
- vmware debian全屏
- 一步一步教你将开源项目上传到jcenter(第二种方式)
- 深度图像信息的应用
- redis集群 实现 tomcat session 共享
- HBASE Rowkey filter
- Hibernate——对象的三种状态
- 【手把手教你全文检索】Apache Lucene初探
- JVM垃圾收集算法(标记-清除、复制、标记-整理)