IO模型

只关注IO,不关注IO读写完成后的事情。

同步:程序(APP)自己进行读/写操作

异步:由Kernel完成读/写,程序跑起来感觉像没有访问IO,访问的是buffer

阻塞:BLOCKING,一直等待着方法有效的返回结果

非阻塞:NONBLOCKING,调用方法的时候就返回是否读取到,(java中要么返回null,要么返回具体的对象)

所以IO模型有:

同步阻塞:程序(APP)自己读取,调用了方法后一直等待着有效的返回结果

同步非阻塞:程序(APP)自己读取,调用方法的瞬间就给出是否读取到的返回结果,这个时候程序要考虑下一次再去读取的问题(比如用while循环)

那么异步呢?异步的只有非阻塞的,(异步阻塞无意义)。其实异步的问题暂时不需要讨论,因为IO模型下,目前Linux没有通用内核的异步处理方案。

NIO和多路复用器

nio 需要全部遍历内核fd(比如处于listen状态的文件描述符),用户态内核态需要切换(一次切换就是一次系统调用)才能实现

多路复用器:多条路(指IO)只通过一个系统调用,获得所有IO(fd)的状态,然后由程序自己对有状态的IO进行R/W操作。只要是程序自己读写,就说明IO模型是同步的

多路复用一般有SELECT,POSIX,POLL,EPOLL,KQUEUE

NIO


多路复用


linux内核多路复用器select,poll,epoll

来看一下底层关于select的描述及api。这里借助于man select指令。

man select

看到描述 select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchronous I/O multiplexing---这里很明确的给出了select的功能含义:同步I/O多路复用

再来几个描述:

An fd_set is a fixed size buffer.  Executing FD_CLR() or FD_SET() with a value of fd that is negative or is equal to or larger than FD_SETSIZE will  result  in undefined behavior.  Moreover, POSIX requires fd to be a valid file descriptor

大致意思是:fd_set是固定大小的缓冲区。如果fd值为负或大于等于FD_SETSIZE,则执行FD_CLR()或FD_SET(),这样会导致不确定的行为。而且,POSIX要求fd是有效的文件描述符。

这里提到了FD_SETSIZE,这是一个固定的数值(1024,2048之类的),这是select要求的,而poll则没有。这也是select和poll的区别。


其实到这里,我们可以得出结论:

无论nio、select、poll都是要遍历所有的IO,询问状态,

但是,

NIO的遍历是需要很多次系统调用的,成本在用户态与内核态的切换上;

而多路复用器select/poll,这个过程触发了一次系统调用,在这次用户态内核态切换的过程中,把fds传递到内核,内核根据这次用户传递过来的fds进行遍历,修改状态。

多路复用器select/poll的弊端:

  1. 每次都要重新重复传递fds(内核开辟空间)

  2. 每次内核被调用了之后,针对这次调用,触发了一个遍历fds全量的复杂度

由此,引入epoll这个牛逼的东西。

还是直接看linux对epoll的描述:

man epoll:


epoll - I/O event notification facility 一看到这个大致知道是和事件通知相关的

epoll API执行与poll类似的任务:监视多个文件描述符以查看其中的任何文件是否可以进行I / O。

epoll_create 创建一个epoll实例并返回引用该实例的文件描述符。

epoll_ctl 通过epoll_ctl注册指定文件描述符集合。

epoll_wait 等待I / O事件,如果当前没有可用的事件,则阻塞调用线程。

画个图和select/poll类比一下


实际结合理论

Java中是如何使用多路复用的?我们用一段程序解释一下。

初始化Server

private ServerSocketChannel server = null;private Selector selector = null;int port = 9090;

public void initServer() {    try {        server = ServerSocketChannel.open();        server.configureBlocking(false);        server.bind(new InetSocketAddress(port));

        selector = Selector.open();

        server.register(selector, SelectionKey.OP_ACCEPT);    } catch (IOException e) {        e.printStackTrace();    }}

Selector 类似于linux下的多路复用器(select poll epoll kqueue),nginx,event{}

server.configureBlocking(false) 设置非阻塞

selector = Selector.open() 如果在epoll模型下,open()相当于前面提到的epoll_create方法,返回一个fd实例---假设是fd3

server.register(selector, SelectionKey.OP_ACCEPT) server约等于处于listen状态的fd---设fd4,对于register:若是select/poll模型,则jvm里开辟一个数组把这个fd放进去;若是epoll,则epoll_ctl(fd3,ADD,fd4,EPOLLIN

Start启动Server,并处理事件

public void start() {    initServer();    System.out.println("服务器启动了。。。。。");    try {        while (true) {            while (selector.select() > 0) {                Set selectionKeys = selector.selectedKeys();                 Iterator iter = selectionKeys.iterator();while (iter.hasNext()) {                    SelectionKey key = iter.next();                    iter.remove(); //set  不移除会重复循环处理if (key.isAcceptable()) {                        acceptHandler(key);                    } else if (key.isReadable()) {                        readHandler(key);                    }                }            }        }    } catch (IOException e) {        e.printStackTrace();    }}

这段代码除了启动server,重要的逻辑是调用多路复用器。

selector.select()

  1. select/poll模型下,select()等于内核的select(fd4)  poll(fd4)
  2. epoll等于内核的 epoll_wait(),这个可以带时间参数。若没有时间或者参数为0表示阻塞,若有时间则设置一个超时。selector.wakeup()  结果返回0

while (iter.hasNext())

这段代码表示,管你是什么多路复用器,你只能给我状态,我的程序还得一个一个的去处理他们的R/W。这就是同步---真的好辛苦!!!!!!!!

if (key.isAcceptable())

这里是重点,如果要去接受一个新的连接,语义上,accept接受连接且返回新连接的FD,那么这个新的FD如何处理?

select/poll,因为他们内核没有空间,那么在jvm中保存和前边的fd4那个listen的一起

epoll:通过epoll_ctl把新的客户端fd注册到内核空间

这个具体看下面acceptHandler这个方法

public void acceptHandler(SelectionKey key) {    try {        ServerSocketChannel ssc = (ServerSocketChannel) key.channel();        SocketChannel client = ssc.accept(); //来啦,目的是调用accept接受客户端  fd7        client.configureBlocking(false);

        ByteBuffer buffer = ByteBuffer.allocate(8192); 

        // 0.0  我类个去        //你看,调用了register        /*        select,poll:jvm里开辟一个数组 fd7 放进去        epoll:  epoll_ctl(fd3,ADD,fd7,EPOLLIN         */        client.register(selector, SelectionKey.OP_READ, buffer);        System.out.println("-------------------------------------------");        System.out.println("新客户端:" + client.getRemoteAddress());        System.out.println("-------------------------------------------");

    } catch (IOException e) {        e.printStackTrace();    }}

这一段和前面的理论知识就对上了,^_^

通过进入linux底层,探查linux多路复用器,有助于很好的理解Java网络编程的多路复用器原理。扒开外表,我们直接看内涵,很多东西理解起来就不那么费劲了。

epoll编程实例客户端_深入底层探析网络编程之多路复用器(select,poll,epoll)相关推荐

  1. epoll编程实例客户端_网络编程:epoll

    前言 前面讲了IO多路复用的API,select和poll的缺点是性能不够,客户端连接越多性能下降越明显,epoll的出现解决了这个问题,引用The Linux Programming Interfa ...

  2. python交互式编程客户端_【python】UDP网络编程:实现服务端与客户端的交互、简单的AI智能模式...

    关于UDP网络编程 UDP(user datagram protocol)的中文叫用户数据报协议,属于传输层.UDP是面向非连接的协议,它不与对方建立连接,而是直接把要发的数据发给对方. [UDP网络 ...

  3. python的网络编程学什么_【Python学习】网络编程

    1 # 1.发get请求 2 import requests 3 url = 'http://api.nnzhp.cn/api/user/stu_info' 4 data = {'stu_name': ...

  4. c++中recvfrom函数_通俗易懂:快速理解网络编程中5种IO模型

    关于IO模型,就必须先谈到几个日常接触的几个与IO相关名字:同步,异步,阻塞,非阻塞. 名词解释 同步 如果事件A需要等待事件B的完成才能完成,这种串行执行机制可以说是同步的,这是一种可靠的任务序列, ...

  5. java nio原理 epoll_多路复用 Select Poll Epoll 的实现原理(BIO与NIO)

    BIO blocking阻塞的意思,当我们在后端开发使用的时候,accetp 事件会阻塞主线程. 当accept事件执行的时候,客户的会和服务建立一个socket 连接.一般后端就会开启一个线程执行后 ...

  6. Java网络编程和NIO详解开篇:Java网络编程基础

    老曹眼中的网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为我们拥有网络.网络是一个神奇的东西,它改变了你和我的 ...

  7. select poll epoll 高效IO 多路转接

    目录 五种常见IO模型 高效IO的概念 阻塞 vs 非阻塞 非阻塞IO fcntl函数 I/O多路转接之select 初识select select函数原型 select操作接口 tcp_server ...

  8. Python之路-python(Queue队列、进程、Gevent协程、Select\Poll\Epoll异步IO与事件驱动)

    一.进程: 1.语法 2.进程间通讯 3.进程池 二.Gevent协程 三.Select\Poll\Epoll异步IO与事件驱动 一.进程: 1.语法 1 简单的启动线程语法 2 def run(na ...

  9. python3 异步 非阻塞 IO多路复用 select poll epoll 使用

    有许多封装好的异步非阻塞IO多路复用框架,底层在linux基于最新的epoll实现,为了更好的使用,了解其底层原理还是有必要的. 下面记录下分别基于Select/Poll/Epoll的echo ser ...

最新文章

  1. 软件测试工程师如何提升自己?
  2. 蓝桥杯 基础练习 十进制转十六进制(水题,进制转换)
  3. 广电系统三八红旗集体推荐材料_【原创】怎么把好几千字的材料压缩成500字?这些方法推荐给你!...
  4. 俄罗斯将封杀LinkedIn 推动个人数据本地化
  5. Oracle C#处理时间类型的Insert
  6. ASP.NET MVC3 中的AJAX
  7. tensorflow2.0 图像处理项目_游戏爱好者应该看看这个开源项目
  8. 【HTML+CSS网页设计与布局 从入门到精通】第14章-float/position/display属性
  9. 【软件使用技巧】PL/SQL Developer实现双击table询
  10. KMP算法------字符串匹配问题
  11. paip.程序模块间的通讯方式大总结
  12. 游戏蛮牛Unity 用户文档
  13. 普鸥知识产权|如何申请美国外观专利?申请费用、时间、流程?
  14. java_home环境变量_配置home环境变量
  15. 【基本算法】穷举算法
  16. PHP 实现word在线预览
  17. python对淘宝运营有帮助吗_淘宝运营,有前途吗?
  18. 网站推荐-极简壁纸网站
  19. M1芯片真正原生版本photoshop 2021安装 PS2021 Mac版 附详细教程!再无需rosetta转译!!
  20. <Zhuuu_ZZ>设计模式—面向接口编程

热门文章

  1. Qt网络编程——TCP
  2. Linux私房菜阅读笔记
  3. C代码工具--自动生成enum值和名字映射代码
  4. mysql setautocommit_MySql 中的setAutoCommit方法
  5. SQL Server 数据类型陷阱
  6. android 更新适配器,android – 当适配器数据更改时更新列表视图
  7. Windows 7,无法访问internet,DNS无响应
  8. IIS优化-解决IIS访问速度慢问题
  9. 【前端 · 面试 】HTTP 总结(四)—— HTTP 状态码
  10. c语言累积乘,C语言编程累积2