很抱歉,这是一篇个人技术笔记。单纯地记录, 没营养
BUFFER:
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
MappedByteBuffer,用于表示内存映射文件
CHANNEL:
FILECHANNEL
DATAGRAMCHANNEL
SOCKETCHANNEL
SERVERSOCKETCHANNEL
涵盖TCP、UDP IO和文件IO
SELECTOR:
在一个Thread中可以用Selector处理多个channel。如果打开了很多连接,每个连接流量很小,可以用。
CHANNEL的数据读写是单向的,可以异步,总是需要BUFFERBUFFER。
关于它们的简单用例如下:
File f
Channel c = f.getChannel()
c.read(new ByteBuff())
c.flip()
scatter()
gather()
channel之间可以直接传输数据:
toChannel.transferFrom(position, count, fromChannel);
fromChannel.transferTo(position, count, toChannel);
Selector概念:
能够检测到多个channel,并能够知晓通道是否为读写做好准备。
为什么使用Selector:
仅用单个线程控制多个channel的优势明显
Selector使用示例:
Selector selector = Selector.open();
channel.configureBlocking(false);
SelectionKey key = channel.register(selector,Selectionkey.OP_READ);
与Selector一起使用时,Channel必须处于非阻塞模式下。这意味着不能将FileChannel与Selector一起使用,因为FileChannel不能切换到非阻塞模式。而套接字通道都可以。
可以监听四种不同类型的事件:
Connect
Accept
Read
Write
通道触发了一个事件意思是该事件已经就绪。所以,某个channel成功连接到另一个服务器称为“连接就绪”。一个server socket channel准备好接收新进入的连接称为“接收就绪”。一个有数据可读的通道可以说是“读就绪”。等待写数据的通道可以说是“写就绪”。
这四种事件用SelectionKey的四个常量来表示:
SelectionKey.OP_CONNECT
SelectionKey.OP_ACCEPT
SelectionKey.OP_READ
SelectionKey.OP_WRITE
SelectionKey中包含
interest集合
ready集合
Channel
Selector
附加的对象(可选)
int interestSet = selectionKey.interestOps();
int readySet = selectionKey.readyOps();
selectionKey.isAcceptable();
selectionKey.isConnectable();
selectionKey.isReadable();
selectionKey.isWritable();
Channel channel = selectionKey.channel();
Selector selector = selectionKey.selector();
select()阻塞到至少有一个通道在你注册的事件上就绪了。
select(long timeout)和select()一样,除了最长会阻塞timeout毫秒(参数)。
selectNow()不会阻塞,不管什么通道就绪都立刻返回(译者注:此方法执行非阻塞的选择操作。如果自从前一次选择操作后,没有通道变成可选择的,则此方法直接返回零。)。
Set selectedKeys = selector.selectedKeys();
selector.wakeUp()
Selector selector = Selector.open();
02channel.configureBlocking(false);
03SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
04while(true) {
05intreadyChannels = selector.select();
06if(readyChannels ==0)continue;
07Set selectedKeys = selector.selectedKeys();
08Iterator keyIterator = selectedKeys.iterator();
09while(keyIterator.hasNext()) {
10SelectionKey key = keyIterator.next();
11if(key.isAcceptable()) {
12// a connection was accepted by a ServerSocketChannel.
13}elseif(key.isConnectable()) {
14// a connection was established with a remote server.
15}elseif(key.isReadable()) {
16// a channel is ready for reading
17}elseif(key.isWritable()) {
18// a channel is ready for writing
19}
20keyIterator.remove();
21}
22}
SocketChannel
打开一个SocketChannel并连接到互联网上的某台服务器。
一个新连接到达ServerSocketChannel时,会创建一个SocketChannel。
打开 SocketChannel
下面是SocketChannel的打开方式:
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
关闭 SocketChannel
当用完SocketChannel之后调用SocketChannel.close()关闭SocketChannel:
socketChannel.close();
打开一个SocketChannel并连接到互联网上的某台服务器。
一个新连接到达ServerSocketChannel时,会创建一个SocketChannel。
打开 SocketChannel
下面是SocketChannel的打开方式:
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
关闭 SocketChannel
当用完SocketChannel之后调用SocketChannel.close()关闭SocketChannel:
socketChannel.close();
ServerSocketChannel
Java NIO中的 ServerSocketChannel 是一个可以监听新进来的TCP连接的通道, 就像标准IO中的ServerSocket一样。ServerSocketChannel类在 java.nio.channels包中。
这里有个例子:
01ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
02
03serverSocketChannel.socket().bind(newInetSocketAddress(9999));
04
05while(true){
06SocketChannel socketChannel =
07serverSocketChannel.accept();
08
09//do something with socketChannel...
10}
datagramChannel
DatagramChannel channel = DatagramChannel.open();
channel.socket().bind(new InetSocketAddress(9999));
channel.connect(new InetSocketAddress("jenkov.com", 80));
pipe
Java NIO 管道是2个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。数据会被写到sink通道,从source通道读取。
这里是Pipe原理的图示: