I/O复用之select
作用:
实现I/O的多路复用
该函数允许进程指示内核等待多个事件中的任何一个发生,并只有在一个或多个事件发生时或经历一段指定的时间后才唤醒它。进程将于select处阻塞,直到被检测的描述符有一个或多个发生了变化。我们可以使用它来监视多个文件描述符的状态变化。
函数原型:
int select(int maxfd,fd_set *rdset,fd_set *wrset, \
fd_set *exset,struct timeval *timeout);
参数:
参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。
下面的宏提供了处理这三种描述词组的方式:
FD_CLR(inr 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的全部位
参数timeout为结构timeval,用来设置select()的等待时间,其结构定义如下:
struct timeval
{
time_t tv_sec;//second
time_t tv_usec;//minisecond
};
这个参数有三种可能:
- 永远等待下去:仅在一个描述符准备号I/O才返回。此时该参数为NULL
- 等待一段固定时间:在有一个描述符准备好I/O时返回,但不超过由该参数所指向的timeval结构中指定的秒数和微秒数。
- 不等待:检查描述符后立即返回。这称为轮询(polling)。此时该参数必须指向一个timeval结构,且两个值为0.
函数返回值
执行成功: 返回文件描述词状态已改变的个数,如果返回0代表在描述词状态改变前已超过timeout时间。
执行失败: 当有错误时返回-1,错误原因存于errno中,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测。错误值可能为:
- EBADF 文件描述词为无效的或该文件已关闭
- EINTR 此调用被信号所中断
- EINVAL 参数n 为负值
- ENOMEM 核心内存不足
示例
这里给出unp中基于select模型的echo服务器。
int main(int argc, char **argv)
{
//服务器初始化
int i, maxi, maxfd, listenfd, connfd, sockfd;
int nready, client[FD_SETSIZE];
ssize_t n;
fd_set rset, allset;
char buf[MAXLINE];
socklen_t clilen;
listenfd = Socket(AF_INET, SOCK_STREAM, 0); //TCP
struct sockaddr_in servaddr = InitSrvSockaddr(SERV_PORT), cliaddr;
Bind(listenfd, (SA *)&servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);
maxfd = listenfd; //此时listenfd为fd最大值
maxi = -1; //index into client array
for (i = 0; i < FD_SETSIZE; ++i)
client[i] = -1; //初始化client数组
FD_ZERO(&allset);
FD_SET(listenfd, &allset); //listenfd 加入allset
for (;;)
{
rset = allset;
nready = Select(maxfd + 1, &rset, NULL, NULL, NULL); //返回状态发生变化的描述符总数
if (FD_ISSET(listenfd, &rset)) //listenfd可用,代表有客户端连接成功
{
clilen = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *)&cliaddr, &clilen);
for (i = 0; i < FD_SETSIZE; ++i) //从开始遍历client数组,找到第一个为-1的位置,将客户的fd保存
if (client[i] < 0) //为-1代表可用
{
client[i] = connfd;
break;
}
if (i == FD_SETSIZE) //已满
err_quit("too many clients");
FD_SET(connfd, &allset);
if (connfd > maxfd)
maxfd = connfd;
if (i > maxi)
maxi = i;
if (--nready <= 0)
continue;
}
for (i = 0; i <= maxi; ++i)
{
if ((sockfd = client[i]) < 2)
continue;
if (FD_ISSET(sockfd, &rset))
{
if ((n = Read(sockfd, buf, MAXLINE)) == 0)
{
Close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
}
else
Writen(sockfd, buf, n);
if (--nready <= 0) //就绪描述符数目为0就跳出,避免检查未就绪的描述符
break;
}
}
}
}
参考自:
http://blog.csdn.net/turkeyzhou/article/details/8609360
《unix网络编程》
I/O复用之select的更多相关文章
- UNIX网络编程——I/O复用:select和poll函数
我们看到TCP客户同时处理两个输入:标准输入和TCP套接字.我们遇到的问题是就在客户阻塞于(标准输入上)fgets调用,服务器进程会被杀死.服务器TCP虽然正确的给客户TCP发送了一个FIN,但是既然 ...
- 并发服务器--02(基于I/O复用——运用Select函数)
I/O模型 Unix/Linux下有5中可用的I/O模型: 阻塞式I/O 非阻塞式I/O I/O复用(select.poll.epoll和pselect) 信号驱动式I/O(SIGIO) 异步I/O( ...
- 【Unix网络编程】chapter6 IO复用:select和poll函数
chapter6 6.1 概述 I/O复用典型使用在下列网络应用场合. (1):当客户处理多个描述符时,必须使用IO复用 (2):一个客户同时处理多个套接字是可能的,不过不叫少见. (3):如果一个T ...
- UNIX网络编程 第6章 I/O复用:select和poll函数
UNIX网络编程 第6章 I/O复用:select和poll函数
- Linux I/O复用中select poll epoll模型的介绍及其优缺点的比較
关于I/O多路复用: I/O多路复用(又被称为"事件驱动"),首先要理解的是.操作系统为你提供了一个功能.当你的某个socket可读或者可写的时候.它能够给你一个通知.这样当配合非 ...
- 【unix网络编程第三版】阅读笔记(五):I/O复用:select和poll函数
本博文主要针对UNP一书中的第六章内容来聊聊I/O复用技术以及其在网络编程中的实现 1. I/O复用技术 I/O多路复用是指内核一旦发现进程指定的一个或者多个I/O条件准备就绪,它就通知该进程.I/O ...
- 第十七篇:IO复用之select实现
前言 在看过前文:初探IO复用后,想必你已对IO复用这个概念有了初步但清晰的认识. 接下来,我要在一个具体的并发客户端中实现它(基于select函数),使得一旦服务器中的客户进程被终止的时候,客户端这 ...
- IO复用之select实现
前言 在看过前文:初探IO复用后,想必你已对IO复用这个概念有了初步但清晰的认识.接下来,我要在一个具体的并发客户端中实现它( 基于select函数 ),使得一旦服务器中的客户进程被终止的时候,客户端 ...
- UNP学习笔记4——I/O复用:select和poll函数
1 概述 之间的学习中发现,传统的阻塞式系统调用不仅浪费进程运行时间,而且会带来狠毒问题.因此进程需要有一种预先告知内核的能力,使得内核一旦发现进程指定的一个或者多个I/O条件就绪,它就通知进程.这个 ...
- linux的IO复用,select机制理解--ongoing
一:首先需要搞清楚IO复用.阻塞的概念: Ref: https://blog.csdn.net/u010366748/article/details/50944516 二:select机制 作为IO ...
随机推荐
- wgrib读grib数据
该文章来自博客:http://windforestwing.blog.163.c ... 412007103084743804/如有错误 ,大家及时指出啊!ps:meteoinfo可以直接处理grib ...
- 《汇编语言 基于x86处理器》第九章字符串与数组部分的代码
▶ 书中第九章的程序,主要讲了字符串相关的输入.输出,以及冒泡排序.二分搜索 ● 代码,Irvine32 中的字符串库函数代码范例 INCLUDE Irvine32.inc .data str1 BY ...
- mapPartitions
mapPartitions操作与 map类似,只不过映射的参数由RDD中的每一个元素变成了RDD中每一个分区的迭代器,如果映射过程需要频繁创建额外的对象,使用mapPartitions操作要比map操 ...
- 16.linux常用查看命令
cat :查看整个文件tail -200f abc.txt :查看abc.txt的最后200行
- 用大白话谈谈XSS与CSRF
这两个关键词也是老生常谈了,但是还总是容易让人忘记与搞混~.XSS与CSRF这两个关键词时常被拉出来一起比较(尤其是面试),我在这里也在写一篇扫盲文,也帮自己整理一下知识脉络. 这篇文章会用尽量“人话 ...
- 分布式存储Seaweedfs源码分析
基于源码版本号 0.67 , [Seaweedfs以前旧版叫Weedfs]. Seaweedfs 是一个非常优秀的由 golang 开发的分布式存储开源项目, 虽然在我刚开始关注的时候它在 githu ...
- 一种去中心化的manager设计思路
通常,我们设计游戏引擎时,或者管理器时,都会由管理器产出各种产品,一旦有新产品要加,就要修改管理器,来增加相应的生成代码. 这从设计上来看有两个问题: 1,管理器参数需要有个类型,在管理器中用if e ...
- mysql分库分区分表
分表: 分表分为水平分表和垂直分表. 水平分表原理: 分表策略通常是用户ID取模,如果不是整数,可以首先将其进行hash获取到整. 水平分表遇到的问题: 1. 跨表直接连接查询无法进行 2. 我们需要 ...
- 原生js上传文件,使用new FormData()
当创建一个内容较多的表单,表单里面又有了文件上传,文件上传也需要表单提交,单一的上传文件很好操作: <form action="接口" enctype="multi ...
- Delphi Class of 类引用
Delphi Class of 类引用也就是类的类型,也可说是指向类的指针 Type TControlCls = Class of TControl;function CreateComponent( ...