netty学习之网络IO篇(一)
很早之前无意之间接触了netty,虽然这东西在工作中几乎很少会使用到,但是这个东西学起来真的很有趣,随着对它的一步步认识,会发现自己对底层的认识真的太浅了。前段时间学习tomcat源码的时候看到tomcat使用NIO处理请求部分时真的是看不懂了,然后又决定重拾NIO,顺便把netty再细化一遍
学习netty首先就是要学习NIO,学习NIO就要了解IO模型、底层操作系统,这就是有意思的地方,需要不断挖掘。
以下是linux中的5种IO模型
讲这几个IO模型之前先了解一个概念,操作系统是为用户提供服务的,也就是为应用提供服务,所以每个应用程序要想访问底层的资源都要先经过操作系统,通过应用程序调用操作系统的函数,不让应用程序直接访问底层硬件资源,这样设计的目的是为了保障计算机的安全。具体看下面这副图
当应用程序需要获取硬盘上、网络上,外设上的数据时,要向操作系统发起请求,然后由操作系统将数据拷贝到操作系统的内存中,也就是内核空间,然后再拷贝到用户空间。这个过程两次数据拷贝,也引出一个概念叫零拷贝,可以将内核缓冲区地址与用户缓冲区地址进行映射,实现内核空间和用户空间的数据共享,就拷贝地址而不用拷贝数据。
1、阻塞IO:首先调用系统recvfrom函数等待数据,直到数据准备好从内核空间复制到用户空间,这个过程该线程不能做任何事情。
2、非阻塞IO:支持一个首先调用系统recvfrom函数等待数据,内核无准备好的数据就直接返回,一直反复去查询是否就绪,直到数据准备好后才把数据复制到用户空间。
3、IO多路复用:这个是重点,java中使用的IO模。首先有个东西称作fd(文件描述符),是linux上的概念,因为在linux上把一切要处理的资源都当做文件去处理,比如一次网络连接就是一个fd,一次文件读取就是一个fd。
a、对于BIO一个对操作系统发起的一次函数调用只能检测一个fd。
b、对于非阻塞IO模型缺点,如果有1000个socket fd同时连接,我理解会导致1000个对操作系统的函数调用去检测内核数据是否准备好了,从而引起cup飙升。
c、对非阻塞模型的优化就是我们要讲的IO多路复用,它对操作系统的一次函数调用(epoll)可以检测到大量的socket描述符(FD),最大值可以通过cat /proc/sys/fs/file-max查看,这样我们的单线程就可以在短时间内接受大量请求。
信号驱动和异步IO我就不描述了。本篇主要是为了搞懂java中的NIO线程模型。理解为什么通过NIO可以提高并发量。