再谈NIO
关键字 NIO
,epoll
,中断
,selector
之前曾经有分享过一篇NIO的学习笔记,更多的是从NIO的概念上加以了解和学习的,现在就来学习下更深层次的东西,先初步了解下操作系统的中断,通过中断了解网卡如何接收到外界的socket,然后socket数据进入到内核中,如何被epoll感知到,最后才是NIO如何通过selector能够让单线程处理大量套接字链接,极大的提高效率,而不再是之前的阻塞式的单线程处理单套接字的情况
1、epoll
众所周知,网卡是和外界进行数据交互的硬件,当网卡接收到外界发送过来的数据时,就会给CPU发送中断事件,告诉CPU有消息发送过来了,然后CPU才可以感知到套接字数据发送过来了。类似于敲键盘这个动作也是键盘这个硬件发送一个中断消息给CPU,然后CPU去处理该消息,才有后面的在屏幕上回显按键信息等操作。
CPU把接收到的数据抽象包装成为一个套接字,然后把其拷贝到内核中。一般情况下套接字也是连接TCP、UDP和应用程序的桥梁,应用程序接收到的都是套接字,里面包含了具体的网络IO流。
可以通过和自己发送数据包的情况验证是否出现断网的情况
而epoll作为在Linux上一种新的poll,可以显著的提高文件处理时的CPU消息,也就可以很好的处理高并发下的socket句柄。
epoll包含了两个重要的数据结构,一个包含所有socket句柄的红黑树,一个包含所有准备好套接字(套接字已经拷贝至内核中)的链表
当CPU接收到一个套接字时,都会被当做一个socket句柄存储到内核中,然后通过epoll的特定函数epoll_ctl
存放到epoll的红黑树上。红黑树本身就是一个O(logn)的二叉查找树,即使在最坏的情况下效率也是非常好的。然后epoll会往内核中断处理程序中注册一个回调函数,告诉内核当这个socket句柄中断到来时,就存放到链表中。
通过上述操作,就可以做到无需轮询遍历所有的socket句柄获取需要的socket句柄,只需要从链表中获取需要的套接字即可
2、selector、NIO
selector是java1.4 NIO 提供的一个类,他可以通过native方法调用到Linux底层支持的epoll所提供的方法,当然在Windows、Linux、Mac等不同的平台具体实现都稍微存在差异
调用selector.select
等方法之后,就可以获取到所有准备包装了就绪的套接字信息的socketchannel,进行后续的业务处理
更多关于epoll的可以看看