一 BIO
1. 网络编程的基本模型是C/S模型,即两个进程间的通信。
2.采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端的连接,它接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理没处理完成后,通过输出流返回应答给客户端,线程销毁。即典型的一请求一应答通宵模型
缺点:
该模型最大的问题就是缺乏弹性伸缩能力,当客户端并发访问量增加后,服务端的线程个数和客户端并发访问数呈1:1的正比关系,Java中的线程也是比较宝贵的系统资源,线程数量快速膨胀后,系统的性能将急剧下降,随着访问量的继续增大,系统最终就死-掉-了。
源码解析:3.服务端:
![09387e423f548aa1d6d4733e4498edae.png](https://img-blog.csdnimg.cn/img_convert/09387e423f548aa1d6d4733e4498edae.png)
BIO服务端
4.客户端线程:
![6400afa8336bc509e6d8262acb4596b2.png](https://img-blog.csdnimg.cn/img_convert/6400afa8336bc509e6d8262acb4596b2.png)
BIO客户端
5.阻塞式I/O创建的客户端:
![64b3fb3b1c1322b59db274e5ad893070.png](https://img-blog.csdnimg.cn/img_convert/64b3fb3b1c1322b59db274e5ad893070.png)
阻塞式I/O创建的客户端
6.输出结果:
![6543c81dd96648b1268983ddb6cf513a.png](https://img-blog.csdnimg.cn/img_convert/6543c81dd96648b1268983ddb6cf513a.png)
BIO结果
总结:
BIO主要的问题在于每当有一个新的客户端请求接入时,服务端必须创建一个新的线程来处理这条链路,在需要满足高性能、高并发的场景是没法应用的(大量创建新的线程会严重影响服务器性能,甚至罢工)
二 NIO
1. 简介:
NIO我们一般认为是New I/O(也是官方的叫法),因为它是相对于老的I/O类库新增的(其实在JDK 1.4中就已经被引入了,但这个名词还会继续用很久,即使它们在现在看来已经是“旧”的了,所以也提示我们在命名时,需要好好考虑),做了很大的改变。但民间跟多人称之为Non-block I/O,即非阻塞I/O,因为这样叫,更能体现它的特点。而下文中的NIO,不是指整个新的I/O库,而是非阻塞I/O。
NIO提供了与传统BIO模型中的Socket和ServerSocket相对应的SocketChannel和ServerSocketChannel两种不同的套接字通道实现。
新增的着两种通道都支持阻塞和非阻塞两种模式。
阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。
对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用NIO的非阻塞模式来开发。
2.缓冲区 Buffer
Buffer是一个对象,包含一些要写入或者读出的数据。
在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的;在写入数据时,也是写入到缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。
缓冲区实际上是一个数组,并提供了对数据结构化访问以及维护读写位置等信息。
具体的缓存区有这些:ByteBuffe、CharBuffer、 ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。他们实现了相同的接口:Buffer。
3.通道 Channel
我们对数据的读取和写入要通过Channel,它就像水管一样,是一个通道。通道不同于流的地方就是通道是双向的,可以用于读、写和同时读写操作。
底层的操作系统的通道一般都是全双工的,所以全双工的Channel比流能更好的映射底层操作系统的API。
Channel主要分两大类:
SelectableChannel:用户网络读写
FileChannel:用于文件操作
4.多路复用器 Selector
Selector是Java NIO 编程的基础。
Selector提供选择已经就绪的任务的能力:Selector会不断轮询注册在其上的Channel,如果某个Channel上面发生读或者写事件,这个Channel就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获取就绪Channel的集合,进行后续的I/O操作。
一个Selector可以同时轮询多个Channel,因为JDK使用了epoll()代替传统的select实现,所以没有最大连接句柄1024/2048的限制。所以,只需要一个线程负责Selector的轮询,就可以接入成千上万的客户端。
源码:
服务端:
![63e738b91c6bc320afafb57b03407c31.png](https://img-blog.csdnimg.cn/img_convert/63e738b91c6bc320afafb57b03407c31.png)
NIO服务端
![4e2c1f1da36be5bceb6207b6a8588995.png](https://img-blog.csdnimg.cn/img_convert/4e2c1f1da36be5bceb6207b6a8588995.png)
NIO服务端
客户端:
![ca06241f13e03dfb2b83dd745868c97e.png](https://img-blog.csdnimg.cn/img_convert/ca06241f13e03dfb2b83dd745868c97e.png)
NIO客户端
![4219902469796d776223602222361800.png](https://img-blog.csdnimg.cn/img_convert/4219902469796d776223602222361800.png)
NIO客户端
NIO综上所述:
1. 打开ServerSocketChannel,监听客户端连接
2. 绑定监听端口,设置连接为非阻塞模式
3. 创建Reactor线程,创建多路复用器并启动线程
4. 将ServerSocketChannel注册到Reactor线程中的Selector上,监听ACCEPT事件
5. Selector轮询准备就绪的key
6. Selector监听到新的客户端接入,处理新的接入请求,完成TCP三次握手,简历物理链路
7. 设置客户端链路为非阻塞模式
8. 将新接入的客户端连接注册到Reactor线程的Selector上,监听读操作,读取客户端发送的网络消息
9. 异步读取客户端消息到缓冲区
10. 对Buffer编解码,处理半包消息,将解码成功的消息封装成Task
11.将应答消息编码为Buffer,调用SocketChannel的write将消息异步发送给客户端
三 AIO
1. 简介:
NIO 2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。
异步的套接字通道时真正的异步非阻塞I/O,对应于UNIX网络编程中的事件驱动I/O(AIO)。他不需要过多的Selector对注册的通道进行轮询即可实现异步读写,从而简化了NIO的编程模型。
AIO太多没法附上源码,需要了解更多请以下操作获取