NIO:non-blocking io
三大组件
channel & Buffer
-
channel是读写数据的双向通道,可以将数据读入到buffer中,也可以将buffer的数据写入到channel
-
常见的channel有:
- FileChannel:文件传输通道
- DatagramChannel:udp数据传输通道
- SocketChannel:tcp客户端数据传输通道
- ServerSocketChannel:tcp数据传输通道
-
常见的buffer有
- ByteBuffer
ByteBuffer
正确使用
ByteBuffer
- 调用
channel.read(buffer)
把数据写入到buffer
中 - 调用
filp()
切换到读模式 - 从
buffer
读取数据,调用buffer.get()
- 调用
clear()
或者compact()
切换到写模式 - 重复1-4的步骤
ByteBuffer的结构
- capacity:容量
- position:索引下标
- limit:读写限制
- 一开始new一个buffer的时候,buffer内容是空,写入的限制和容量是一样大的,position是在开头
- 当写模式下,我们写入四个数据,position会随着写入的数据而位置发生改变,写入限制和容量都不会变
- filp切换到读模式之后,position会从头开始读取数据,limit切换到读能读取到的范围(不会读到空)
- 如果读取完所有的数据,再clear切换到写模式下,position、limit、capacity都会和原来空的时候的位置一模一样
- 如果调用的是compact方法,这个时候还没有没有读完的数据,就会把这些数据压缩到首位,再重新写数据
selector
-
多线程版的服务器端:一个线程处理一个客户端连接,但是这样连接数增加,会导致内存占用会随着连接数的增加而消耗,甚至瘫痪;线程的切换会导致成本提高。所以这种多线程版服务器端只适合于连接数比较少的情况。
-
线程池版的服务器端:socket是工作再阻塞模式下,使用线程池的服务器端,可以限制线程池的数量,但是缺点是:阻塞模式下,线程只能处理一个
socket
连接,也就是说socket1
在连接的时候,即使这个连接没有读写请求,socket3
是不能被处理的,必须要等到socket1
断开才可以被处理。这种比较适合短连接情况,如http请求。
-
selector
版的服务器端:selector
的作用是配合一个线程来管理多个channel
,获取channel
上发生的事情,这些channel
是工作再非阻塞模式下的,这种适合连接数量比较多,但是流量比较低的场景