使用select函数的套接字
如果你想保持现有连接的同时,侦听新的连接,怎么办呢?
普通的做法(使用recv, accept是做不到的)。当使用accetp等待新的连接时,程序是阻塞的,也就没办法再同原有连接保持通信。
另一种做法是,使用非阻塞方式,但这会浪费了宝贵的CPU时间(你的不停的轮询轮询)。
有没有更好的办法呢?答案是肯定的 – 使用select函数。
select可以帮助你同时监听多个套接字。它会告诉你哪个套接字读数据就绪, 哪个套接字写数据就绪,哪个套接字发生错误。
使用select意味着使用I/O多路技术。

select函数头文件:
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

select函数原型:
int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
详细信息可查看 man select
select()函数的参数说明:
numfds 是readfds,writefds,exceptfds 中fd 集合中文件描述符中最大的数字加上1。
readfds 中的fd 集合将由select 来监视是否可以读取。
writefds 中的fds 集合将由select 来监视是否可以写入。
exceptfds 中的fds 集合将由select 来监视是否有例外发生。
timeout 是用来设置等待超时的
返回值:
如果成功,则返回就绪的文件描述符的数量。超时一般返回0。错误返回-1。
这个timeval 结构定义如下:
struct timeval
{
int tv_sec ; /* 秒数 */
int tv_usec ; /* 微秒 */
} ;
只需要将tv_sec 设置为你想等待的秒数,然后设置tv_usec 为想等待的微秒数(真正
的时间就是tv_sec 所表示的秒数加上tv_usec 所表示的微秒数)。当select()函数返回的时候,timeval 中的时间将会被设置为执行为select()后还剩下的时间。

如果你想知道是是否可以从标准输入和一些套接字(sockfd)中读取数据,你就可以把文件描述符和sockfd 加入readfds 中。numfds 的数值设成readfds 中文件描述符中最大的那个加上一,也就是sockfd+1(因为标准输入的文件描述符的值为0 ,所以其他任何的文件描述符都会比标准输入的文件描述符大)。
当select()函数返回的时候,readfds 将会被修改用来告诉你哪一个文件描述符你可以用来读取数据。使用FD_ISSET() 宏,你可以选出select()函数执行的结果。

处理fd_set的宏:
FD_ZERO(fd_set *set)将一个文件描述符集合清零
FD_SET(int fd, fd_set *set)将文件描述符fd 加入集合set 中 – 这样select就会去监听它的状态。
FD_CLR(int fd, fd_set *set)将文件描述符fd 从集合set 中删除 – select不再去监听它的状态。
FD_ISSET(int fd, fd_set *set)检测fd在fdset集合中的状态是否变化。当检测到fd状态发送变化时返回真,否则,返回假。

下面程序,等待从标准输入输入数据,并打印所输入的数据。如果3秒内没输入(输入回车才算输入就绪),则打印超时或出错。

View Code

#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>int main(int argc, char **argv)
{fd_set fdsets;FD_ZERO(&fdsets);FD_SET(STDIN_FILENO, &fdsets);struct timeval timeout;timeout.tv_sec = 5;timeout.tv_usec = 0;char buff[50];if (select(2, &fdsets, NULL, NULL, &timeout)>0){if (FD_ISSET(STDIN_FILENO, &fdsets)){scanf("%s", buff);printf("has input\n");}}else{printf("timeout or error!\n");}return 0;
}

下面是使用select同时侦听多个连接的例子:

View Code

#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#define PORT 1234
#define MAXSOCKFD 10
int main(int argc, char **argv)
{int sockfd,newsockfd,is_connected[MAXSOCKFD],fd;struct sockaddr_in addr;int addr_len = sizeof(struct sockaddr_in);fd_set readfds;char buffer[256];char msg[ ] ="Welcome to server!";if ((sockfd = socket(AF_INET,SOCK_STREAM,0))<0){perror("socket"); exit(1); }bzero(&addr,sizeof(addr));addr.sin_family =AF_INET;addr.sin_port = htons(PORT);addr.sin_addr.s_addr = htonl(INADDR_ANY);if(bind(sockfd,&addr,sizeof(addr))<0){perror("connect");exit(1);}if(listen(sockfd,3)<0){perror("listen"); exit(1); }for(fd=0;fd<MAXSOCKFD;fd++) is_connected[fd]=0;while(1){ FD_ZERO(&readfds); FD_SET(sockfd,&readfds); //用于侦听新连接for(fd=0;fd<MAXSOCKFD;fd++) {if(is_connected[fd]) FD_SET(fd,&readfds);  //已处理的连接加入select侦听
        }if(!select(MAXSOCKFD,&readfds,NULL,NULL,NULL))continue;for(fd=0;fd<MAXSOCKFD;fd++) {if(FD_ISSET(fd,&readfds)){if(sockfd = =fd) //一个未处理的连接
                {if((newsockfd = accept (sockfd,&addr,&addr_len))<0) perror("accept");write(newsockfd,msg,sizeof(msg));is_connected[newsockfd] =1;printf("cnnect from %s\n",inet_ntoa(addr.sin_addr));}else //已处理的连接有读就绪
                { bzero(buffer,sizeof(buffer)); if(read(fd,buffer,sizeof(buffer))<=0) //读数据失败,表明连接关闭
                    {printf("connect closed.\n");is_connected[fd]=0;close(fd);}else //成功读取数据printf("%s",buffer);}}}}
}

转载于:https://www.cnblogs.com/uvsjoh/archive/2012/07/18/2596804.html

select - I/O多路复用相关推荐

  1. select函数--IO多路复用详解

    本章基于网络编程,需要学习网络编程的可以看我这篇博客: socket编程(超简单.详细.可运行)–实现一个简单的聊天程序 什么是多路复用IO呢? 多路io:允许同时对多个I/O进行控制 可能这样说还是 ...

  2. php io select,Python IO多路复用之——select方案服务端和客户端代码【python源码详解】...

    准备文件: IO.py  服务端代码 tcp_c.py 客户端代码 IO.py 代码: from select import * #引入 select 模块 from socket import * ...

  3. c/c++实现一个密集型server/socket多路复用select

    作一个tcp的服务程序,同时可能有大量的客户端连上来,希望分别记住各个socket 谁有数据过来,就读出来,放到一个请求队列--这些事情用一个线程完成 另外有一个结果队列,如果结果里包含了socket ...

  4. python-IO多路复用,select模块

    触发机制:1)水平触发:2)边缘触发 IO多路复用单线程实现并发,实现模块:1)select(效率最低): 2)poll:3)epoll(最好,nginx的实现).linux下有这3种模块,windo ...

  5. io多路复用的原理和实现_IO多路复用的三种机制:select 、poll 、epoll

    目录 概述 IO多路复用本质 IO多路复用的优势 IO多路复用Select机制 IO多路复用Poll机制 IO多路复用Epoll机制 select,poll,epoll机制区别总结 php7进阶到架构 ...

  6. select 多路复用

    目录 一.循环接收多个信道的问题 二.select详解 一.循环接收多个信道的问题 在使用通道时,想同时接收多个通道的数据是一件困难的事情.通道在接收数据时,如果没有数据可以接收将会发生阻塞. 虽然可 ...

  7. 【经典】5种IO模型 | IO多路复用

    上篇回顾:静态服务器+压测 3.2.概念篇 1.同步与异步 同步是指一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成. 异步是指不需要等待被依赖的任务完成,只是通 ...

  8. select、poll、epoll之间的区别(搜狗面试)

    (1)select==>时间复杂度O(n) 它仅仅知道了,有I/O事件发生了,却并不知道是哪那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对 ...

  9. IO多路复用原理剖析

    (最近笔试遇到笔试题:select,poll,epoll都是IO多路复用的机制). I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应 ...

最新文章

  1. 最全的 Spring 依赖注入方式,你都会了吗?
  2. 【CyberSecurityLearning 47】PHP 数组
  3. 赠书 | 什么是 Knative?
  4. config设置源 使用pip_python pip源配置
  5. 软件测试桌面检查,静态测试的主要方法 - 测试天下,梦寻人生 - 51Testing软件测试网 51Testing软件测试网-软件测试人的精神家园...
  6. LeetCode 413 等差数列划分
  7. Linux查看哪些进程占用较多的cpu、内存和磁盘IO的方法
  8. 消费级GPU、速度提升3000倍,微软FastNeRF实现200FPS
  9. 工程验收工作笔记0002---可以提供等保服务的几个平台
  10. 现代操作系统读书笔记
  11. Matlab仿真002-一阶电路
  12. jinja模板简介与概述
  13. 狮子座与摩羯座 ---转载
  14. 电脑热点突然不能用了,想想你是否新装了VMware等软件
  15. html arm音频播放器,web页面播放arm格式音频
  16. 一个猫下面的计算机互相访问,光猫连接路由器和电脑如何互相访问
  17. 兔子繁殖 c语言编程,c语言写的兔子繁殖- 斐波那契数列.每次只显示前两个.
  18. PHP 常用英语精简1
  19. 多国拟发ChatGPT禁令 关“野兽”的笼子要来了?
  20. 大数据背景下网络信息安全分析探讨

热门文章

  1. crosstool-ng构建的一个错误的解决
  2. Linux下载安装zookeeper
  3. php 将数据库导出为csv,php – 将数据库转换为CSV并将文件保存到服务器上的文件夹 - 程序园...
  4. 【Flink】Flink 源码之时间处理
  5. 【Flink】Flink 1.10之改进的TaskManager内存模型与配置
  6. 【Elastischearch】7.6 版本 update 后 refresh 慢,性能问题导致稳定性问题
  7. 【java】java 8 的一些集合操作
  8. 【Elasticsearch】所有可用 Qbox 插件概述:第一部分
  9. 【ambari】Ambari 环境安装
  10. 04-linux下安装neo4j