要想学习netty就先要了解:(网络编程模型:BIO、NIO、AIO)
上图的工作模式:
请求数据时,IO操作通常包括两个部分(使用到的IO模型如下)
阻塞IO:程序请求操作系统IO,如果内核缓冲区中没有准备好数据,进程则会进行等待。
非阻塞IO:程序请求操作系统IO,如果内核缓冲区中没有准备好数据,进程会继续执行,不断进行系统调用直到IO数据准备好。
同步IO:操作系统收到程序请求后,如果内核缓冲区中没有准备好数据,进程不会响应,直到数据准备好才会响应往下执行。
异步IO:操作系统收到程序请求后,如果内核缓冲区中没有准备好数据,会返回一个标记,程序继续往下执行。当数据准备好之后,会以事件的方式通知。
应用进程被阻塞,直到内核缓冲区中的数据复制到应用进程缓冲区中才返回。
应用进程执行系统调用之后,内核返回一个错误码。应用进程可以继续执行,但是需要不断的执行系统调用来获知I/O是否完成,这种方式称为轮询。(polling)。
1、使用select或者poll等待数据,并且可以等待多个套接字中的任何一个变为可读,这一过程会被阻塞,当某一个套接字可读时返回,之后再使用recvfrom 把数据从内核复制到进程中。
2、使用select或者poll,可以让单个进程具有处理多个I/O事件的能力。
多路复用的实现:select、poll、epoll,这些函数都是系统调用函数。
select工作原理:
select存在的问题:
它和select 的主要区别就是,去掉了select只能监听1024个客户端的限制。
epoll对select和poll进行了优化:
由于Linux下没有Windows下的IOCP技术提供真正的异步IO支持,所以Linux下使用epoll模拟异步IO
1、应用进程使用sigaction系统调用,内核立即返回,应用进程可以继续执行,也就是说等待数据阶段应用进程是非阻塞的。
2、内核在数据到达时向应用进程发送SIGIO信号,应用进程收到之后在信号处理程序中调用 recvfrom 将数据从内核复制到应用进程中。
进行aio_read系统调用会立即返回,应用进程继续执行,不会被阻塞,内核会在所有操作完成之后向应用进程发送信号。
Java BIO:同步并阻塞,服务器采用线程池为一个客户端连接创建一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销。
Java NIO:同步非阻塞(IO多路复用),服务器实现模式为一个线程处理多个请求(连接),即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有 I/O 请求就进行处理。
Java AIO(NIO.2):异步非阻塞,AIO 引入异步通道的概念,采用了 Rector/Proactor 模式,当用户态访问内核会立即返回一个标记,由内核会在所有操作完成之后向应用进程发送信号,一般适用于连接数较多且连接时间较长的应用。
channel类
channel类中几个重要的方法
缓冲区(Buffer):缓冲区本质上是一个可以读写数据的内存块,可以理解成是一个容器对象(含数组),该对象提供了一组方法,可以更轻松地使用内存块,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况。对文件的读取或写入都必须经由Buffer。
buffer的子类
Buffer缓冲区有两种工作模式
buffer缓冲区中的四大属性
需要使用buffer.flip反转读模式和写模式
写模式
读模式
1、Selector能够检测多个注册的通道上是否有事件发生(注意:多个Channel 以事件的方式可以注册到同一个Selector),如果有事件发生,便获取事件然后针对每个事件进行相应的处理。这样就可以只用一个单线程去管理多个通道,也就是管理多个连接和请求。
2、使用selector检测,当通道中有事件发生时会主动通知selector,可以减少多线程之间的上下文切换(1个selector系统调用+N次就绪的客户端的read系统调用)。
传统做法是需要循环访问所有通道是否有事件发生,这样在数据量大的情况下,会导致消耗内存资源严重
Selector相关方法说明
selector.select(); //阻塞
selector.select(1000); //阻塞 1000 毫秒,在 1000 毫秒后返回
selector.wakeup(); //唤醒 selector
selector.selectNow(); //不阻塞,立马返还
作者:阿宁你好啊
原文链接:https://www.cnblogs.com/worldusemycode/p/16010084.html