作者前言:在学习i/o复用前,我们要清楚为什么要引出I/O复用,它的的作用是什么?什么是I/O复用?I/O复用是怎么实现的? -------  想一想噢~

下面我来解释一下这些问题

I/O复用的作用

从进程线程的学习,到多进程多线程,再到进程池线程池,我们处理事件的效率越来越高,但是却有一个问题,一直都没有解决,那就是,当服务器分配了一个线程或进程为某一个客户端服务时,该进程或线程就相当于与这个客户端绑定了,除非客户端断开连接,否则不管有没有请求事件,这个线程或进程都只能为这个客户端处理事件。我们知道,系统允许我们创建的线程或进程是有限的,那么这样就会造成资源的浪费,所以我们需要实现一套机制,在客户端没有请求事件的时候,该进程或线程就可以去处理其他客户端的事件,也就是我们需要将多个文件描述符同时监听,当有请求时,去处理发出请求的客户端的事件。由此就有了I/O复用。

什么是I/O复用

I/O复用的本质就是一个线程监听多个文件描述符,我们可以这样理解,多线程多进程编程,就是老师对学生一对一辅导,但是不是所有时候学生都有问题,这样老师就会很闲,会浪费很大的师资力量,而I/O复用,就相当于一个老师辅导多个学生,学生有问题提出问题(发出请求事件),老师处理完就可以处理别的学生的问题了。那就有人说了,I/O理解起来太麻烦,我用循环,轮询一遍就能找到该处理哪个事件了,但是你见过有老师一个一个问学生你有问题吗,如果老师知道有人有问题就挨个问一遍,他还有力气处理问题么,同样的道理,我们的CPU那么忙碌,它是来处理事件的,又不是挨个打招呼的,所以我们就直接告知CPU处理哪个问题就ok啦。

通过上面举例,我们可以理解,I/O复用的两个优点(划重点、面试官会问的呐)

1. 它减少了进程或线程的创建数量,节省了我们的内存资源,使得资源更加高效的被利用。

2. 它减少了CPU的工作压力,CPU只需要做自己最擅长的事就好。

 I/O复用的应用场景

1.客户端程序要同时处理多个socket。

2.客户端程序要同时处理用户输入和网络连接。

3.TCP服务器要同时处理监听socket和连接socket。

4.服务器要同时处理TCP请求和UDP请求。

5.服务器要同时监听多个端口,或者处理多种服务。

需要指出的是,I/O复用虽然能够同时监听多个文件描述符,但它本身是阻塞的。并且当多个文件描述符同时就绪时,如果不采取额外的措施,程序就只能按顺序依次处理其中的每一个文件描述符,这使得服务器程序看起来像是串行工作的。如果要实现并发,只能使用多进程或多线程等编程手段。

I/O复用的实现

在linux下I/O复用的实现主要有三个系统调用:select,poll,epoll(epoll为linux特有)

1.select系统调用

select系统调用的用途是:在一段指定时间内,监听用户感兴趣的文件描述符上的可读、可写和异常等事件。

select系统调用的原型:
#include<sys/select.h>
int select(int nfds,fd_set* readfds,fd_set* writefds,fd_set* exceptfds,struct timeval * timeout);

nfds:最大文件描述符的值+1
readfds:用户感兴趣的可读事件的文件描述符集合
writefds:可写事件的文件描述符集合
exceptfds:异常事件的文件描述符集合
timeout:设置超时时间 ,如果timeout为NULL,则select一直阻塞

返回值: >0    返回就绪文件描述符的个数
               ==0   超时
               == -1 出错

用户程序必须自己保存所有的文件描述符

select每次都会将所有的文件描述符返回,返回后还必须循环探测具体哪些是就绪的文件描述符。

每次调用select都必须重新设置resdfds、writefds、exceptfds

fd_set结构体的定义         ---------->       int fds[32];      按位表示关注的文件描述符

每次最多可以监听1024个文件描述符,并且其最大值1023

文件描述符就绪条件:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/select.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>//初始化维护的数组,用于保存文件描述符
void init_fd(int *fds,int len)
{int i = 0;for(; i < len ;++i){fds[i] = -1;}
}
//往维护的数组里面添加文件描述符
void insert_fd(int *fds,int fd,int len)
{int i = 0;for(;i < len ;++i){if(fds[i] == -1){fds[i] = fd;break;}}
}
//删除文件描述符
void delete_fd(int *fds,int fd,int len)
{int i = 0;for(; i < len ;++i){if(fds[i] == fd){fds[i] = -1;break;}}
}int main()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);assert(sockfd != -1);struct sockaddr_in saddr,caddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("127.0.0.1");int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));assert(res != -1);listen(sockfd,5);fd_set readfds;int fds[100];init_fd(fds,100);insert_fd(fds,sockfd,100);while(1){int maxfd = -1;FD_ZERO(&readfds);//先将文件描述符清空int i = 0;for(; i < 100;++i){if(fds[i] != -1){if(fds[i] > maxfd){maxfd = fds[i];}FD_SET(fds[i],&readfds);}}int n = select(maxfd+1,&readfds,NULL,NULL,NULL);if(n <= 0){printf("select fail\n");continue;}for(i = 0;i<100;++i){if(fds[i] != -1 && FD_ISSET(fds[i],&readfds)){if(fds[i] == sockfd)//客户链接{int len = sizeof(caddr);int c = accept(sockfd,(struct sockaddr *)&caddr,&len);if(c < 0){printf("one client over\n");continue;}insert_fd(fds,c,100);}else //客户请求{int fd = fds[i];char buff[128] = {0};int n = recv(fd,buff,127,0);if(n <= 0){delete_fd(fds,fd,100);close(fd);continue;}printf("%d : %s\n",fd,buff);send(fd,"OK",2,0);  }}}}
}

I/O复用 —— select相关推荐

  1. 使用多线程还是用IO复用select/epoll? epoll 或者 kqueue 的原理是什么?

    原作者:蓝形参 原文:http://www.zhihu.com/question/20114168/answer/14024115 使用多线程还是用IO复用select/epoll? 多线程模型适用于 ...

  2. I/O复用:select和poll函数

    <UNIX网络编程卷1:套接字联网API(第3版)> - 第6章- I/O复用 I/O模型 在介绍select和poll两个函数之前, 整体回顾下Unix下5种I/O模型的基本区别 阻塞式 ...

  3. 第6章 I/O复用 select 和 poll 函数

    I/O 复用的能力: 如果一个或多个 I/O 条件满足(例如,输入已准备好被读,或者描述字可以承接更多的输出)时,我们就被通知到. I/O 复用由函数 select 和 poll 支持. I/O 复用 ...

  4. 020303阶段三 I/O复用 select和epoll的文件描述符管理

    目录 一.学习的知识点 1 五种 I/O 1.1 阻塞式I/O 1.2 非阻塞式I/O 1.3 I/O复用(select 和pool) 1.3.1 select 文件描述符的管理 select 缺点 ...

  5. I/O复用-select

    I/O复用 I/O复用的功能就是同时监听多个文件描述符,这样的话程序性能就能得到大大提升.通常,网络程序在下列情况下需要使用I/O复用技术: 服务端程序要同时处理多个socket. 服务端程序要同时处 ...

  6. php socket select IO复用

    此篇博客是接着上篇php socekt阻塞模型PHP代码(php socket IO阻塞方式的Server/Client)的进阶,IO阻塞模型只能是同一个时刻只能由一个客户端进行访问,除非利用多进程或 ...

  7. linux平台IO多路复用 select接口使用例子

    这几天在学习net-snmp源码,里面封装了很多select函数调用,这里记录一下linux上select的用法以及相关接口. 先看接口: //头文件 #include <sys/select. ...

  8. poll函数_I/O复用 - 三组I/O复用函数的比较

    在之前的文章中 I/O复用 - epoll 和 I/O复用 - select&poll 中我们讨论了三组I/O复用的系统调用,这3组系统调用都能同时监听多个文件描述符.它们将等待由timeou ...

  9. 【精辟】socket阻塞与非阻塞,同步与异步,select,pool,epool

    socket阻塞与非阻塞,同步与异步 作者:huangguisu 1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调 ...

最新文章

  1. python学习笔记 - StringIO以及BytesIO
  2. 【转载】从百度、360、搜狗对新站态度看国内搜索引擎技术现状
  3. 文档被保存但是语音识别的数据丢失
  4. vue xxx was assigned to but it has no setter.
  5. 带Spring Boot的GWT
  6. 【Hihocoder - 1723】子树统计(线性基合并)
  7. c语言中的运算符及其含义_按位运算符及其在C语言中与Example一起使用
  8. asp.net 用正则表达式过滤内容中的电话,qq,email
  9. 拥抱ARM妹子 序章!ARM妹子~~ 哥我来啦!
  10. Windows运行程序时桌面窗口卡死
  11. 清华大学张亚勤对话朱民:颠覆认知的AI时代及产业机遇
  12. [词一首]【相思难断】
  13. 目标检测, 实例分割, 图像分类, panoptic segmentation文献
  14. k8s学习笔记——ceph rbd本地手动挂载
  15. String字符串分割的3种方法 Java
  16. 时间序列分析实验报告总结_时间序列实验报告.doc
  17. Unity游戏开发——新发教你做游戏(三):3种资源加载方式
  18. 微服务架构最重要的 10 个设计模式!
  19. [内附完整源码和文档] 基于python的新闻检索系统
  20. 运用arcGIS ArcPy推求管网节点高程

热门文章

  1. 评测酷睿i5 1240p和锐龙r5 6600u选哪个 i51240p和锐龙r56600u对比
  2. Excel如何统计同一单元格内姓名个数
  3. 12、加权平均队列(WFQ-Weight Fair Queue)算法
  4. 视频的帧率和分辨率以及码率的关系
  5. 南电转债上市价格预测
  6. 折半插入排序顺序结构
  7. Python-Flask实战项目一:仿知乎轻量级web问答平台搭建
  8. 数智化转型赋能方法论与服务路径
  9. python-机器学习-手写数字识别
  10. 3.css3深入,高级选择器浮动布局,html5/css3基础开始(推荐收藏)