作用:

实现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的更多相关文章

  1. UNIX网络编程——I/O复用:select和poll函数

    我们看到TCP客户同时处理两个输入:标准输入和TCP套接字.我们遇到的问题是就在客户阻塞于(标准输入上)fgets调用,服务器进程会被杀死.服务器TCP虽然正确的给客户TCP发送了一个FIN,但是既然 ...

  2. 并发服务器--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( ...

  3. 【Unix网络编程】chapter6 IO复用:select和poll函数

    chapter6 6.1 概述 I/O复用典型使用在下列网络应用场合. (1):当客户处理多个描述符时,必须使用IO复用 (2):一个客户同时处理多个套接字是可能的,不过不叫少见. (3):如果一个T ...

  4. UNIX网络编程 第6章 I/O复用:select和poll函数

    UNIX网络编程 第6章 I/O复用:select和poll函数

  5. Linux I/O复用中select poll epoll模型的介绍及其优缺点的比較

    关于I/O多路复用: I/O多路复用(又被称为"事件驱动"),首先要理解的是.操作系统为你提供了一个功能.当你的某个socket可读或者可写的时候.它能够给你一个通知.这样当配合非 ...

  6. 【unix网络编程第三版】阅读笔记(五):I/O复用:select和poll函数

    本博文主要针对UNP一书中的第六章内容来聊聊I/O复用技术以及其在网络编程中的实现 1. I/O复用技术 I/O多路复用是指内核一旦发现进程指定的一个或者多个I/O条件准备就绪,它就通知该进程.I/O ...

  7. 第十七篇:IO复用之select实现

    前言 在看过前文:初探IO复用后,想必你已对IO复用这个概念有了初步但清晰的认识. 接下来,我要在一个具体的并发客户端中实现它(基于select函数),使得一旦服务器中的客户进程被终止的时候,客户端这 ...

  8. IO复用之select实现

    前言 在看过前文:初探IO复用后,想必你已对IO复用这个概念有了初步但清晰的认识.接下来,我要在一个具体的并发客户端中实现它( 基于select函数 ),使得一旦服务器中的客户进程被终止的时候,客户端 ...

  9. UNP学习笔记4——I/O复用:select和poll函数

    1 概述 之间的学习中发现,传统的阻塞式系统调用不仅浪费进程运行时间,而且会带来狠毒问题.因此进程需要有一种预先告知内核的能力,使得内核一旦发现进程指定的一个或者多个I/O条件就绪,它就通知进程.这个 ...

  10. linux的IO复用,select机制理解--ongoing

    一:首先需要搞清楚IO复用.阻塞的概念: Ref:  https://blog.csdn.net/u010366748/article/details/50944516 二:select机制 作为IO ...

随机推荐

  1. wgrib读grib数据

    该文章来自博客:http://windforestwing.blog.163.c ... 412007103084743804/如有错误 ,大家及时指出啊!ps:meteoinfo可以直接处理grib ...

  2. 《汇编语言 基于x86处理器》第九章字符串与数组部分的代码

    ▶ 书中第九章的程序,主要讲了字符串相关的输入.输出,以及冒泡排序.二分搜索 ● 代码,Irvine32 中的字符串库函数代码范例 INCLUDE Irvine32.inc .data str1 BY ...

  3. mapPartitions

    mapPartitions操作与 map类似,只不过映射的参数由RDD中的每一个元素变成了RDD中每一个分区的迭代器,如果映射过程需要频繁创建额外的对象,使用mapPartitions操作要比map操 ...

  4. 16.linux常用查看命令

    cat :查看整个文件tail -200f  abc.txt  :查看abc.txt的最后200行

  5. 用大白话谈谈XSS与CSRF

    这两个关键词也是老生常谈了,但是还总是容易让人忘记与搞混~.XSS与CSRF这两个关键词时常被拉出来一起比较(尤其是面试),我在这里也在写一篇扫盲文,也帮自己整理一下知识脉络. 这篇文章会用尽量“人话 ...

  6. 分布式存储Seaweedfs源码分析

    基于源码版本号 0.67 , [Seaweedfs以前旧版叫Weedfs]. Seaweedfs 是一个非常优秀的由 golang 开发的分布式存储开源项目, 虽然在我刚开始关注的时候它在 githu ...

  7. 一种去中心化的manager设计思路

    通常,我们设计游戏引擎时,或者管理器时,都会由管理器产出各种产品,一旦有新产品要加,就要修改管理器,来增加相应的生成代码. 这从设计上来看有两个问题: 1,管理器参数需要有个类型,在管理器中用if e ...

  8. mysql分库分区分表

    分表: 分表分为水平分表和垂直分表. 水平分表原理: 分表策略通常是用户ID取模,如果不是整数,可以首先将其进行hash获取到整. 水平分表遇到的问题: 1. 跨表直接连接查询无法进行 2. 我们需要 ...

  9. 原生js上传文件,使用new FormData()

    当创建一个内容较多的表单,表单里面又有了文件上传,文件上传也需要表单提交,单一的上传文件很好操作: <form action="接口" enctype="multi ...

  10. Delphi Class of 类引用

    Delphi Class of 类引用也就是类的类型,也可说是指向类的指针 Type TControlCls = Class of TControl;function CreateComponent( ...