一:五种I/O模型区分:

  1、阻塞I/O模型

       最流行的I/O模型是阻塞I/O模型,缺省情形下,所有套接口都是阻塞的。我们以数据报套接口为例来讲解此模型(我们使用UDP而不是TCP作为例子的原因在于就UDP而言,数据准备好读取的概念比较简单:要么整个数据报已经收到,要么还没有。然而对于TCP来说,诸如套接口低潮标记等额外变量开始活动,导致这个概念变得复杂)。

  进程调用recvfrom,其系统调用直到数据报到达且被拷贝到应用进程的缓冲区中或者发生错误才返回,期间一直在等待。我们就说进程在从调用recvfrom开始到它返回的整段时间内是被阻塞的。

  2、非阻塞I/O模型

   进程把一个套接口设置成非阻塞是在通知内核:当所请求的I/O操作非得把本进程投入睡眠才能完成时,不要把本进程投入睡眠,而是返回一个错误。也就是说当数据没有到达时并不等待,而是以一个错误返回。

  3、I/O复用模型

    调用select或poll,在这两个系统调用中的某一个上阻塞,而不是阻塞于真正I/O系统调用。 阻塞于select调用,等待数据报套接口可读。当select返回套接口可读条件时,调用recevfrom将数据报拷贝到应用缓冲区中。

  4、信号驱动I/O模型

    首先开启套接口信号驱动I/O功能,并通过系统调用sigaction安装一个信号处理函数(此系统调用立即返回,进程继续工作,它是非阻塞的)。当数据报准备好被读时,就为该进程生成一个SIGIO信号。随即可以在信号处理程序中调用recvfrom来读数据报,井通知主循环数据已准备好被处理中。也可以通知主循环,让它来读数据报。

  5、异步I/O模型

  告知内核启动某个操作,并让内核在整个操作完成后(包括将数据从内核拷贝到用户自己的缓冲区)通知我们。这种模型与信号驱动模型的主要区别是:            信号驱动I/O:由内核通知我们何时可以启动一个I/O操作,            异步I/O模型:由内核通知我们I/O操作何时完成。

二:关于I/O多路复用:

  I/O多路复用(又被称为“事件驱动”),首先要理解的是,操作系统为你提供了一个功能,当你的某个socket可读或者可写的时候,它可以给你一个通知。这样当配合非阻塞的socket使用时,只有当系统通知我哪个描述符可读了,我才去执行read操作,可以保证每次read都能读到有效数据而不做纯返回-1和EAGAIN的无用功。写操作类似。操作系统的这个功能通过select/poll/epoll之类的系统调用来实现,这些函数都可以同时监视多个描述符的读写就绪状况,这样,**多个描述符的I/O操作都能在一个线程内并发交替地顺序完成,这就叫I/O多路复用,这里的“复用”指的是复用同一个线程。

  目前支持I/O复用的系统调用有select、pselect、poll、epoll:

1.I/O复用之select

  1.1 select简介

  select系统调用的目的是:在一段指定时间内,监听用户感兴趣的文件描述符上的可读、可写和异常事件。poll和select应该被归类为这样的系统调用,它们可以阻塞地同时探测一组支持非阻塞的IO设备,直至某一个设备触发了事件或者超过了指定的等待时间——也就是说它们的职责不是做IO,而是帮助调用者寻找当前就绪的设备。

  Unix网络编程中对select模型的原理图如下:

    

  1.2 select函数接口

  #include <sys/time.h>
  #include <sys/types.h>
  #include <unistd.h>
  int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

  fd_set结构体是文件描述符集,该结构体实际上是一个整型数组,数组中的每个元素的每一位标记一个文件描述符。fd_set能容纳的文件描述符数量由FD_SETSIZE指定,一般情况下,FD_SETSIZE等于1024,这就限制了select能同时处理的文件描述符的总量。

  1)nfds参数指定被监听的文件描述符的总数。通常被设置为select监听的所有文件描述符中最大值加1(maxfd1);

  2)readfds、writefds、exceptfds分别指向可读、可写和异常等事件对应的文件描述符集合。这三个参数都是传入传出型参数,指的是在调用select之前,用户把关心的可读、可写、或异常的文件描述符通过FD_SET(下面介绍)函数分别添加进readfds、writefds、exceptfds文件描述符集,select将对这些文件描述符集中的文件描述符进行监听,如果有就绪文件描述符,select会重置readfds、writefds、exceptfds文件描述符集来通知应用程序哪些文件描述符就绪。这个特性将导致select函数返回后,再次调用select之前,必须重置我们关心的文件描述符,也就是三个文件描述符集已经不是我们之前传入 的了。
  3)timeout参数用来指定select函数的超时时间

struct timeval
{
long tv_sec; //秒数
long tv_usec; //微秒数
};

  1.3 select机制部分实现库函数

void FD_SET(int fd, fd_set *set);   //设置需要select检测的文件描述符。如:sock_fd,connect_fd OR 标准输入-stdin
void FD_CLR(int fd, fd_set *set); //清除set中的fd位
int FD_ISSET(int fd, fd_set *set); //判断set中是否设置了文件描述符fd
void FD_ZERO(fd_set *set); //清空set中的所有位(在使用文件描述符集前,应该先清空一下)
//(注意FD_CLR和FD_ZERO的区别,一个是清除某一位,一个是清除所有位)

  1.4 select返回值情况

  1)如果指定timeout为NULL,select会永远等待下去,直到有一个文件描述符就绪,select返回;
  2)如果timeout的指定时间为0,select根本不等待,立即返回;
  3)如果指定一段固定时间,则在这一段时间内,如果有指定的文件描述符就绪,select函数返回,如果超过指定时间,select同样返回。
  4)返回值情况:
    a)超时时间内,如果文件描述符就绪,select返回就绪的文件描述符总数(包括可读、可写和异常),如果没有文件描述符就绪,select返回0;
    b)select调用失败时,返回 -1并设置errno,如果收到信号,select返回 -1并设置errno为EINTR。

  1.6 IO select服务端代码

#include    "unp.h"

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;
struct sockaddr_in cliaddr, servaddr; listenfd = Socket(AF_INET, SOCK_STREAM, ); bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT); Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); Listen(listenfd, LISTENQ); maxfd = listenfd; /* initialize */
maxi = -; /* index into client[] array */
for (i = ; i < FD_SETSIZE; i++)
client[i] = -; /* -1 indicates available entry */
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
/* end fig01 */ /* include fig02 */
for ( ; ; ) {
rset = allset; /* structure assignment */
nready = Select(maxfd+, &rset, NULL, NULL, NULL); if (FD_ISSET(listenfd, &rset)) { /* new client connection */
clilen = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
#ifdef NOTDEF
printf("new client: %s, port %d\n",
Inet_ntop(AF_INET, &cliaddr.sin_addr, , NULL),
ntohs(cliaddr.sin_port));
#endif for (i = ; i < FD_SETSIZE; i++)
if (client[i] < ) {
client[i] = connfd; /* save descriptor */
break;
}
if (i == FD_SETSIZE)
err_quit("too many clients"); FD_SET(connfd, &allset); /* add new descriptor to set */
if (connfd > maxfd)
maxfd = connfd; /* for select */
if (i > maxi)
maxi = i; /* max index in client[] array */ if (--nready <= )
continue; /* no more readable descriptors */
} for (i = ; i <= maxi; i++) { /* check all clients for data */
if ( (sockfd = client[i]) < )
continue;
if (FD_ISSET(sockfd, &rset)) {
if ( (n = Read(sockfd, buf, MAXLINE)) == ) {
/*4connection closed by client */
Close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -;
} else
Writen(sockfd, buf, n); if (--nready <= )
break; /* no more readable descriptors */
}
}
}
}

I/O复用select 使用简介的更多相关文章

  1. 五种I/O模型和select函数简介

    一.五种I/O模型 1.阻塞I/O 我们在前面所说的I/O模型都是阻塞I/O,即调用recv系统调用,如果没有数据则阻塞等待,当数据到来则将数据从内核空间(套接口缓冲区)拷贝到用户空间(recv函数提 ...

  2. 转:五种I/O模型和select函数简介

    源地址:http://blog.csdn.net/jnu_simba/article/details/9070955 一.五种I/O模型 1.阻塞I/O 我们在前面所说的I/O模型都是阻塞I/O,即调 ...

  3. I/O复用-select模型

    IO复用: I/O复用使得程序可以同时监听多个文件描述符,这对提高程序的性能至关重要.例如TCP服务器要同时处理监听socket和连接socket,客户端要同时处理用户输入和网络连接. Linux下实 ...

  4. I/O复用——select和poll

    概述 I/O多路复用(multiplexing)的本质是通过一种机制(系统内核缓冲I/O数据),让单个进程可以监视多个文件描述符,一旦某个描述符就绪(一般是读就绪或写就绪),能够通知程序进行相应的读写 ...

  5. I/O复用----select

    2018-07-31 (星期二)I/O复用:    一个应用程序通常需要服务一个以上的文件描述符.    例如stdin,stdout,进程间通信以及若干文件进行I/O,如果不借助线程的话,(线程通常 ...

  6. Datatable的Select()方法简介

    DataTable是我们在进行开发时经常用到的一个类,并且经常需要对DataTable中的数据进行筛选等操作,下面就介绍一下Datatable中经常用到的一个方法——Select,微软提供了四个函数的 ...

  7. C# Datatable.Select()用法简介

    dt为一个DataTable,以dt为例说明dt.select()方法的功能: 1.dt.Select() 获取所有行数 例:Datarow[] drs=dt.Select(); 此时drs为dt数据 ...

  8. io复用select方法编写的服务器

    摘要:io多路复用是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般都是读就绪或者写就绪),就能通知应用程序进行相应的读写操作.select函数作为io多路复用的机制,第一个参数nfds是f ...

  9. I/O复用(select)——回声服务器端/客户端

    一.select 使用select函数可以将多个文件描述符集中到一起统一监视,监视事件如下: 是否存在待读取数据. 是否可传输无阻塞传输数据. 是否发生异常. 将关心上述3种事件的文件描述发分别注册到 ...

随机推荐

  1. iconfont字体图标的使用方法

    转载于https://www.cnblogs.com/hjvsdr/p/6639649.html 我之前因为项目用bootstrap比较多,所以使用font awesome字体图标比较多,后来接触到了 ...

  2. AcWing 230. 排列计数 水题(组合数+错排)打卡

    题目:https://www.acwing.com/problem/content/232/ #include<bits/stdc++.h> #define ll long long #d ...

  3. Weblogic console控制台密码更改后导致重启服务失败

    weblogic版本10.3.3.0 更改控制台密码后,服务重启失败,报错如下: ----------------------------------------------------------- ...

  4. 57、saleforce学习笔记(四)

    List类 List在这里就是一个类 List<String> lists = new String[]{'1','3'}; List<String> list1 = new ...

  5. SQL Server2012创建连接服务器到ORACLE11G

    做ETL,肯定少不了经常会从不同的数据库直接进行数据的操作,为了更好的进行跨库操作,SQL SERVER 2012拥有LinkedServer功能.前段时间写了个SQL SERVER同种数据库直接的链 ...

  6. C#变量2

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. 数据类型: (1).值类型 类型名称 CTS类型 说明 范围 ^ - ^-(--) ^-^-(-~) ^-^- ^-^- -(-^-) - ...

  7. mysql 5.7.20 动态sql 传入参数

    drop procedure test; delimiter ;; CREATE procedure test() -- 取动态sql的值 -- 目前只测试出,在 where 后面, 可以用 ?,类似 ...

  8. linux/unix下setuid/seteuid/setreuid/setresuid

    其中setresuid()具有最清晰的语法: setresuid()被执行的条件有: ①当前进程的euid是root ②三个参数,每一个等于原来某个id中的一个 如果满足以上条件的任意一个,setre ...

  9. mac 完全卸载vscode

    原文分隔线====================== while writing go this morning, I found that the wrong code are not under ...

  10. 微信小程序の小程序事件流

    一.什么是事件? 事件是视图层到逻辑层的通讯方式:事件可以将用户的行为,反馈到逻辑层进行处理:事件可以绑定在组件上,触发事件后,就会执行逻辑层中对应的事件处理函数:事件对象可以携带额外信息. 二.事件 ...