Select server

  linux 的socket函数分为阻塞和非阻塞两种方式,比如accept函数,在阻塞模式下,它会一直等待有客户连接。而在非阻塞情况下,会立刻返回。我们一般都希望程序能够运行在非阻塞模式下。一种方法就是做一个死循环,不断去查询各个socket的状态,但是这样会浪费大量的cpu时间。解决这个问题的一个方法就是使用select函数。使用select函数可以以非阻塞的方式和多个socket通信。当有socket需要处理时,select函数立刻返回,期间并不会占用cpu时间。

  select函数原型:

//Select 函数原型int select(nfds, readfds, writefds, exceptfds, timeout)//nfds: select监视的文件句柄数,视进程中打开的文件数而定,一般设为呢要  监视各文件中的最大文件号加一//readfds:select监视的可读文件句柄集合//writefds:select监视的可写文件句柄集合。//exceptfds:select监视的异常文件句柄集合。//timeout:本次select的超时结束时间。

  当readfds或writefds中映象的文件可读或可写或超时,本次select() 就结束返回。程序员利用一组系统提供的宏在select()结束时便可判 断哪一文件可读或可写。对Socket编程特别有用的就是readfds.

  select相关函数:

FD_ZERO(fd_set *fdset)
//清空fdset与所有文件句柄的联系。
 
FD_SET(int fd, fd_set *fdset)
//建立文件句柄fd与fdset的联系。
 
FD_CLR(int fd, fd_set *fdset)
//清除文件句柄fd与fdset的联系。
 
FD_ISSET(int fd, fdset *fdset)
//检查fdset联系的文件句柄fd是否可读写,>0表示可读写。

  具体步骤:

//大致如下:……int sockfd;
fd_set fdR;
int sock_fd[N];//save client_sockfd, size is Nstruct timeval timeout;while(1){ FD_ZERO(&fdR);FD_SET(sockfd, &fdR);switch (select(sockfd + 1,&fdR, NULL, &timeout)) {case -1:error;case 0:timeout;default:if (FD_ISSET(sockfd, &fdR)) { now  read or recv something; }}  
/* if sock_serv is in &fdR, now accept() */if( FD_ISSET(sock_serv,&fdR) ){sock_fd[..] = now accept();}
}

  具体代码:

void select_server::starListen()
{int flag = listen(sock_serv, 5);if(flag < 0){perror("listen error!\n");close(sock_serv);return;}printf("listen!\n");fd_set client_fdset;    //监控文件描述符集合int maxsock;            //监控文件描述符中最大的文件号struct timeval tv;        //超时返回时间int client_sockfd[5];   //存放活动的sockfdbzero((void*)client_sockfd,sizeof(client_sockfd));int conn_amount = 0;    //用来记录描述符数量maxsock = sock_serv;char buffer[1024];while(1){//初始化文件描述符号到集合FD_ZERO(&client_fdset);//加入服务器描述符FD_SET(sock_serv,&client_fdset);//设置超时时间tv.tv_sec = 30; //30秒tv.tv_usec = 0;//把活动的句柄加入到文件描述符中for(int i = 0; i < 5; ++i){//程序中Listen中参数设为5,故i必须小于5if(client_sockfd[i] != 0){FD_SET(client_sockfd[i], &client_fdset);}}//printf("put sockfd in fdset!\n");//select函数flag = select(maxsock+1, &client_fdset, NULL, NULL, &tv);if(flag < 0){perror("select error!\n");break;}else if(flag == 0){printf("timeout!\n");continue;}//轮询各个文件描述符for(int i = 0; i < conn_amount; ++i){//FD_ISSET检查client_sockfd是否可读写,>0可读写if(FD_ISSET(client_sockfd[i], &client_fdset)){printf("start recv from client[%d]:\n",i);flag = recv(client_sockfd[i], buffer, 1024, 0);if(flag <= 0){printf("client[%d] close\n", i);close(client_sockfd[i]);FD_CLR(client_sockfd[i], &client_fdset);client_sockfd[i] = 0;}else{printf("recv from client[%d] :%s\n", i, buffer);}}}//检查是否有新的连接,如果收,接收连接,加入到client_sockfd中if(FD_ISSET(sock_serv, &client_fdset)){//接受连接struct sockaddr_in client_addr;size_t size = sizeof(struct sockaddr_in);int sock_client = accept(sock_serv, (struct sockaddr*)(&client_addr), (unsigned int*)(&size));if(sock_client < 0){perror("accept error!\n");continue;}//把连接加入到文件描述符集合中if(conn_amount < 5){client_sockfd[conn_amount++] = sock_client;bzero(buffer,1024);strcpy(buffer, "this is server! welcome!\n");send(sock_client, buffer, 1024, 0);printf("new connection client[%d] %s:%d\n", conn_amount, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));bzero(buffer,sizeof(buffer));flag = recv(sock_client, buffer, 1024, 0);if(flag < 0){perror("recv error!\n");close(sock_serv);return;}printf("recv : %s\n",buffer);if(sock_client > maxsock){maxsock = sock_client;}else{printf("max connections!!!quit!!\n");break;}}}}for(int i = 0; i < 5; ++i){if(client_sockfd[i] != 0){close(client_sockfd[i]);}}
}

  源码:这里


本文 由 cococo点点 创作,采用 知识共享 署名-非商业性使用-相同方式共享 3.0 中国大陆 许可协议进行许可。欢迎转载,请注明出处:
转载自:cococo点点 http://www.cnblogs.com/coder2012

Server Develop (四) select实现非阻塞sever相关推荐

  1. 深度好文:select与非阻塞IO

    对于面向连接的socket类型(SOCK_STREAM,SOCK_SEQPACKET)在读写数据之前必须建立连接,首先服务器端socket必须在一个客户端知道的地址进行监听,也就是创建socket之后 ...

  2. 5种网络IO模型:阻塞IO、非阻塞IO、异步IO、多路复用IO、信号驱动IO

    目录 前言 阻塞IO(blocking IO) 非阻塞IO(non-blocking IO) 多路复用IO(IO multiplexing) 异步IO(Asynchronous I/O) 模型间的区别 ...

  3. 阻塞和非阻塞IO,异步和同步IO

    从网上看到一遍比较好的博客介绍阻塞和非阻塞IO,异步和同步IO的区别和各自的使用场景,虽然是从网络套接字方面解析的,不过也是适合于对驱动文件的操作,毕竟套接字的本质也是一个文件描述符. 转载内容 本文 ...

  4. 使用NIO实现异步非阻塞Socket tcp通信

    使用NIO实现异步非阻塞Socket tcp通信 一.BIO与NIO IO(BIO)和NIO区别:其本质就是阻塞和非阻塞的区别 阻塞概念:应用程序在获取网络数据的时候,如果网络传输数据很慢,就会一直等 ...

  5. 阻塞IO、非阻塞IO的区别

    阻塞IO.非阻塞IO的区别 1.类与类之间的关系:依赖,实现,泛化(继承),关联,组合,聚合. 1)依赖(虚线):一个类是 另一个类的函数参数 或者 函数返回值. 2)实现(实线加小圆):对纯虚函数类 ...

  6. socket connect阻塞和非阻塞处理

    建立socket后默认connect()函数为阻塞连接状态,在大多数实现中,connect的超时时间在75s至几分钟之间,想要缩短超时时间,可解决问题的两种方法:方法一.将socket句柄设置为非阻塞 ...

  7. python非阻塞输入_python_非阻塞套接字及I/O流

    首先,我们要明确2个问题: 普通套接字实现的服务端有什么缺陷吗? 有,一次只能服务一个客户端! 这种缺陷是如何造成的? accept阻塞:当没有套接字连接请求过来的时候会一直等待着 recv阻塞:当连 ...

  8. linux下网络编程设置非阻塞,UNIX网络编程 非阻塞connect的实现

    一.<UNIX网络编程>-非阻塞connect 在一个TCP套接口被设置为非阻塞之后调用connect,connect会立即返回EINPROGRESS错误,表示连接操作正在进行中,但是仍未 ...

  9. socket编程 —— 非阻塞socket (转)---例子已上传至文件中

    在上一篇文章 <socket编程--一个简单的例子> http://blog.csdn.net/wind19/archive/2011/01/21/6156339.aspx 中写了一个简单 ...

  10. JAVA 中IO总结 之前篇阻塞、非阻塞

    最近总结JAVA中的IO,遇到了有关阻塞.非阻塞.同步.异步的概念,之前也做个内核有关开发,今天温故而知新. Linux支持同步IO,也支持异步IO,因此分为同步阻塞.同步非阻塞,异步阻塞,异步非阻塞 ...

最新文章

  1. ConfigParser
  2. 脐带血要不要保存?看了你就明白!
  3. #讲座#低碳经济0814
  4. boost::math::students_t用法的测试程序
  5. JAVA_HOME系统环境变量
  6. 虚函数和虚表指针的例子
  7. 设计模式(14)-Flyweight Pattern
  8. 简化的插入排序 (15 分)
  9. Python基础8—常用模块
  10. 面向对象【day07】:新式类和经典类(八)
  11. 关于php正则表达式得选择题,经典PHP笔试题
  12. Revit API取得全部元素
  13. 【SENCHA TOUCH】页面动画跳转切换
  14. kubeedge v1.1.0部署指南
  15. python谁的教程好贴吧_python深挖65万人的明星贴吧,探究上万个帖子的秘密
  16. DDLMS-DFE算法
  17. e^x导数为什么是e^x
  18. stm32入门开发板选野火还是正点原子好,哪个的视频讲到好一点?
  19. ODOO芯片制造委外加工业自动化解决方案
  20. 好心替同事接电话?小心接出事情来!

热门文章

  1. css 注释写法注意事项
  2. M1 :Mac已可使用Parallels Desktop 16支持Windows
  3. Movie Thumbnails Maker Mac(MTM)使用指南
  4. 关于TeamViewer中的ITbrain
  5. python学习 day2
  6. jquery ajax中文编码设置
  7. 10个最新优秀手机应用界面设计实例
  8. Linux系统管理员命令:sudo
  9. JAVA B/S系统实现客户端屏幕截图,Java版的QQ截图
  10. 给java虚拟机增加一个属性,java -D