1、用户空间和内核空间

操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也可以访问底层硬件设备。为了保护用户进程不能直接操作内核,保证内核的安全,操作系统将虚拟空间划分为两部分,一部分是内核空间,一部分是用户空间。

2、进程切换

内核挂起当前正在cpu上运行的进程,并恢复以前挂起的某个进程的执行。

  • 保存处理机上下文,包括程序计数器和其它寄存器。
  • 更新PCB信息
  • 把进程的PCB移入到相应的队列,如就绪或阻塞队列
  • 选择另一个进程执行,并更新PCB
  • 更新内存管理的数据结构
  • 恢复上下文

3、进程阻塞

正在执行的进程,由于期待某些事件的发生,比如IO,自动执行阻塞原语,进入阻塞状态。这是一种主动行为,只有运行中的进程才可以切换到阻塞状态。在阻塞状态的进程是不占用CPU资源的。

4、I/O模式

标准I/O,数据会先被拷贝到操作系统的内核缓冲区,然后才会从操作系统的内核缓冲区拷贝到应用程序的地址空间。

linux有五种网络模式:

  • 阻塞I/O
  • 非阻塞I/O
  • I/O多路复用
  • 信号驱动I/O(signal driven i/o,不常用)
  • 异步I/O

1、阻塞I/O

用户进程调用recvfrom系统调用,进程进入阻塞状态,等待数据准备好,数据会从内核拷贝到用户内存,然后内核返回结果,用户进程解除block状态,重新运行。

2、非阻塞I/O

用户进程调用read操作,如果数据还没准备好,内核立刻返回error,用户进程不会阻塞。用户进程可以通过反复调用read操作轮询来获得数据。

3、I/O多路复用

I/O multiplexing,也就是select、poll、epoll,也可以被称为event driven I/O。好处是单个进程可以处理多个网络I/O,原理就是select、poll、epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达时,就通知用户进程。

用户进程调用了select,整个进程会被block,同时,kernel会监听所有负责的socket,当有一个socket的数据准备好了,select会返回,用户进程再调用read操作,将数据从内核拷贝到用户进程。如果处理的并发连接数不是很高,使用select、poll、epoll的服务端性能不一定比使用multi-threading + blocking IO的服务端性能好。I/O多路复用时,每一个socket,一般设置为非阻塞模式。

5、I/O多路复用

  • select

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)

select函数监视的文件描述符分3类,分别是readfds、writefds、exceptfds。调用select函数会阻塞,直到有描述符就绪或者超时,函数返回。当select函数返回后,可以通过遍历fdset,找到就绪的描述符。

select可以良好的跨平台。缺点是单个进程能够监视的文件描述符的数量存在最大限制。在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制。

  • poll

int poll(struct pollfd *fds, unsigned int nfds, int timeout)
struct pollfd {
int fd;
short events; // requested events to watch
short revents; //returned events witnessed
}

pollfd结构包含了要监视的event和发生的event,不再使用select『参数-值』传递的方式。pollfd没有最大数量限制,但仍需要轮询返回的pollfd来获取就绪的文件描述符。随着监视的文件描述符数量的增长,效率也会线性下降。

  • epoll

    和select、poll相比,epoll更加灵活,没有描述符的限制。epoll使用一个文件描述符管理多个描述符,将用户进程的文件描述符事件存放在内核的一个事件表中,这样在用户空间和内核空间只需copy一次。

int epoll_create(int size)

创建一个epoll的句柄,size用来告诉内核监听的数目。size并不是限制了epoll所能监听的最大描述符个数,只是对内核初始分配内部数据结构的一个建议。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

函数对指定描述符fd执行op操作。op取值由三个宏表示:添加EPOLL_CTL_ADD,删除EPOLL_CTL_DEL,修改EPOLL_CTL_MOD。epoll_event告诉内核需要监听什么事。

typedef union epoll_data {
void *ptr;
int fd;
_uint32_t u32;
_uint64_t u64;
} epoll_data_t;
struct epoll_event {
_uint32_t events;
epoll_data_t data;
}; //epoll events
EPOLLIN:表示对应的文件描述符可读(包括对端SOCKET正常关闭)
EPOLLOUT: 表示对应的文件描述符可写
EPOLLPRI: 表示对应的文件描述符有紧急数据可读(带外数据)
EPOLLERR: 表示对应的文件描述法发生错误
EPOLLHUP: 表示对应的文件描述法被挂起
EPOLLET: 设置为边缘触发
EPOLLONESHOT: 只监听一次事件,当监听完这次事件后,如果还需要监听这个socket,需要再次把这个socket加入epoll
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)

参数events表示内核得到的事件的集合。maxevents告知内核这个events有多大,取值不能大于创建epoll_create()时的size。参数timeout时超时时间(ms,0表示立刻返回,-1表示不确定,也有说法是永久堵塞)。该函数返回需要处理的事件数目,如返回0表示已超时。

6、epoll工作模式

两种:LT(level trigger), ET(edge trigger)。缺省是LT。

  • LT: 当epoll_wait检测到描述符事件发生时,将此事件通知应用程序。应用程序可以不立即处理该事件,下次调用epoll_wait时,会再次响应应用程序并通知。
  • ET: 当epoll_wait检测到描述符事件发生时,将此事件通知应用程序。应用程序必须立即处理该事件,下次调用epoll_wait时,不会再次通知此事件。

LT是缺省工作模式,支持block和non-block socket。ET是高速工作模式,只支持non-block。

7、总结

在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描。epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。epoll监视的描述符的数量不受限制,它所支持的FD上限是系统最大可打开文件数目。

i/o多路复用笔记的更多相关文章

  1. 7.24 IO多路复用和协程代码笔记

    1. 复习 # !/usr/bin/env python # !--*--coding:utf-8 --*-- # !@Time :2018/7/23 11:49 # !@Author TrueNew ...

  2. Java IO学习笔记六:NIO到多路复用

    作者:Grey 原文地址:Java IO学习笔记六:NIO到多路复用 虽然NIO性能上比BIO要好,参考:Java IO学习笔记五:BIO到NIO 但是NIO也有问题,NIO服务端的示例代码中往往会包 ...

  3. Java IO学习笔记七:多路复用从单线程到多线程

    作者:Grey 原文地址:Java IO学习笔记七:多路复用从单线程到多线程 在前面提到的多路复用的服务端代码中, 我们在处理读数据的同时,也处理了写事件: public void readHandl ...

  4. python学习笔记-(十四)I/O多路复用 阻塞、非阻塞、同步、异步

    1. 概念说明 1.1 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心是内核,独立于普通的应用程序,可 ...

  5. HTTP/2笔记之流和多路复用

    零.前言 本部分将讲解HTTP/2协议中对流的定义和使用,其实就是在说HTTP/2是若何做到多路复用的. 一.流和多路复用的关系 1. 流的概念 流(Stream),服务器和客户端在HTTP/2连接内 ...

  6. python 学习笔记12(事件驱动、IO多路复用、异步IO)

    阻塞IO和非阻塞IO.同步IO和异步IO的区别 讨论背景:Linux环境下的network IO. 1.先决条件(几个重要概念) 1.1.用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32 ...

  7. python学习笔记10--协程、IO、IO多路复用

    本节内容 一.协程 1.1.协程概念 1.2.greenlet 1.3.Gevent 1.4.协程之爬虫 1.5.协程之socket 二.论事件驱动与异步IO 三.IO 3.1.概念说明 3.2.IO ...

  8. io多路复用,select,笔记

    一下代码,是摘自大王的博客,(http://www.cnblogs.com/alex3714/)我自己有加了些注释. 1 2 3 #_*_coding:utf-8_*_ 4 5 __author__ ...

  9. STM32学习笔记——OLED屏

    STM32学习笔记--OLED屏 OLED屏的特点: 1.  模块有单色和双色可选,单色为纯蓝色,双色为黄蓝双色(本人选用双色): 2.  显示尺寸为0.96寸 3.  分辨率为128*64 4.   ...

随机推荐

  1. vue项目中一些文件的作用

    原文 简书原文:https://www.jianshu.com/p/38749e5bec3c 大纲 1.vue项目结构 2.主要的配置文件 2.1.package.json 2.2.dev-serve ...

  2. 得到INI文件所有Section(所有节点名称)

    char SectionNames[MAX_PATH],*pSectionName; ZeroMemory(SectionNames,MAX_PATH); GetPrivateProfileSecti ...

  3. Android——WebView方式开发web App

    昨天接到个酬劳丰厚的任务.把java新生系统做成webApp,想想蛮简单的.所以当时就装作非常为难的样子答应了. 所谓Web App,用曾经我那个老PM的话来说.就是在壳里面套上页面.这里的壳相当于浏 ...

  4. [CSS] Control Image Aspect Ratio Using CSS

    Resize images and videos to fill their parent and maintain their aspect ratio with pure CSS. The new ...

  5. PL/SQL精明的调用栈分析

    PL/SQL精明的调用栈分析 原文:http://www.oracle.com/technetwork/issue-archive/2014/14-jan/o14plsql-2045346.html ...

  6. error: { "$err" : "not master and slaveOk=false", "code" : 13435 }

    rsguo:SECONDARY> db.users.find();error: { "$err" : "not master and slaveOk=false&q ...

  7. 最简单的基于FFmpeg的移动端样例:IOS HelloWorld

    ===================================================== 最简单的基于FFmpeg的移动端样例系列文章列表: 最简单的基于FFmpeg的移动端样例:A ...

  8. 在云平台上基于Go语言+Google图表API提供二维码生成应用

    二维码能够说已经深深的融入了我们的生活其中.到处可见它的身影:但通常我们都是去扫二维码, 曾经我们分享给朋友一个网址直接把Url发过去,如今我们能够把自己的信息生成二维码再分享给他人. 这里就分享一下 ...

  9. 解决Eclipse 启动后总是Building WorkSpace(sleeping)

    打开eclipse后eclipse总是在Building WorkSpace(sleeping),我的解决方案是,Project -> Building AutoMatically关闭就好了,以 ...

  10. Chrome源代码结构

    首先,开始接触Chrome的童鞋可能有一个疑惑,Chrome和Chromium是同一个东西吗?答案是,Chrome是Google官方的浏览器项目名称,Chromium是Google官方对Chrome开 ...