基于nio socket的简单流程:
可以把nio api设计认为 都是通过注册事件和channel: 并轮询检测事件来触发后续操作的。
先把服务器通道serverChannel的 OP_ACCEPT 事件注册到选择器selector上 。
每个客户端 连接 都会使该事件就绪。
就创建一个 socketChannel 来接受(accept)连接。
创建socketChannel通道后,在将自身和其读或写事件 再注册到selector选择器。
后续通过遍历来监听读写事件是否就绪来通知该channel。
注册了之后 内核才能给channel发送内核缓冲区的数据是否完成的通知 。
上面提到了三种事件:
OP_ACCEPT事件 通过serverChannel注册, 用来创建针对每个连接的socketChannel。
读或写事件 通过socketChannel注册。用来读和写。
遍历事件:
selector.select方法来遍历得到就绪的事件 并处理。
如果有就绪的事件,则遍历SelectionKey 获取到每个SelectionKey 来处理 准备好的各种事件 。
由于遍历的对象是SelectionKey 而通过readyKey.channel() 方法就能获取之前注册的channel。
读写的数据:在socketChannel 注册事件的时候的第三个参数。就是创建一个ByteBuffer
socketChannel.register(selector, SelectionKey.OP_READ , ByteBuffer.allocate(2048));
可以把某个对象附着在 SelectionKey上,或是包含聚集数据的某个对象 这样就可以通过该key绑定的SocketChannel 来操作缓冲的数据。
socketChannel.read()和write方法的参数只有ByteBuffer。
aio的简单流程:
AsynchronousServerSocketChannel的accept 方法创建一个 ServerSocketChannelHandle 接受客户端的连接。相当于是注册了一个accept事件, 当有客户端的连接时会触发accept事件就绪,并回调ServerSocketChannelHandle的 completed方法。 该方法返回一个 用于与该连接通信的通道 socketChannel 和 attachment。
而nio 中是通过selector检测事件是否就绪,然后轮询获取对象处理。
在completed 方法中 调用socketChannel的read方法。其中创建了一个SocketChannelReadHandle 。用来处理read读取完成后通过回调通知用户线程。
这一步相当于是注册了read事件,并注册了事件处理器readhandler。当read事件就绪时,内核会直接进行读取操作 读取完成后 就调用事件回调方法通知用户线程。
而nio中是 先检测事件是否就绪,然后轮询获取对象处理,如果read事件就绪 就操作该对象 以阻塞的方法 读取。 这些就会阻塞用户线程。
关键的异同就是
1 java api层面上看,一个事件就绪 是通过轮询的方式还是通过回调的方式响应 以进行后续操作。
2 nio中获得读写事件就绪后进行的读写操作是在用户线程中做的,会阻塞当前线程。而aio 的读写操作是内核中做的,并通过回调通知用户线程。 读操作是指把内核缓冲区的数据读到用户线程。
可以把nio api设计认为 都是通过注册事件和channel: 并轮询检测事件来触发后续操作的。
先把服务器通道serverChannel的 OP_ACCEPT 事件注册到选择器selector上 。
每个客户端 连接 都会使该事件就绪。
就创建一个 socketChannel 来接受(accept)连接。
创建socketChannel通道后,在将自身和其读或写事件 再注册到selector选择器。
后续通过遍历来监听读写事件是否就绪来通知该channel。
注册了之后 内核才能给channel发送内核缓冲区的数据是否完成的通知 。
上面提到了三种事件:
OP_ACCEPT事件 通过serverChannel注册, 用来创建针对每个连接的socketChannel。
读或写事件 通过socketChannel注册。用来读和写。
遍历事件:
selector.select方法来遍历得到就绪的事件 并处理。
如果有就绪的事件,则遍历SelectionKey 获取到每个SelectionKey 来处理 准备好的各种事件 。
由于遍历的对象是SelectionKey 而通过readyKey.channel() 方法就能获取之前注册的channel。
读写的数据:在socketChannel 注册事件的时候的第三个参数。就是创建一个ByteBuffer
socketChannel.register(selector, SelectionKey.OP_READ , ByteBuffer.allocate(2048));
可以把某个对象附着在 SelectionKey上,或是包含聚集数据的某个对象 这样就可以通过该key绑定的SocketChannel 来操作缓冲的数据。
socketChannel.read()和write方法的参数只有ByteBuffer。
aio的简单流程:
AsynchronousServerSocketChannel的accept 方法创建一个 ServerSocketChannelHandle 接受客户端的连接。相当于是注册了一个accept事件, 当有客户端的连接时会触发accept事件就绪,并回调ServerSocketChannelHandle的 completed方法。 该方法返回一个 用于与该连接通信的通道 socketChannel 和 attachment。
而nio 中是通过selector检测事件是否就绪,然后轮询获取对象处理。
在completed 方法中 调用socketChannel的read方法。其中创建了一个SocketChannelReadHandle 。用来处理read读取完成后通过回调通知用户线程。
这一步相当于是注册了read事件,并注册了事件处理器readhandler。当read事件就绪时,内核会直接进行读取操作 读取完成后 就调用事件回调方法通知用户线程。
而nio中是 先检测事件是否就绪,然后轮询获取对象处理,如果read事件就绪 就操作该对象 以阻塞的方法 读取。 这些就会阻塞用户线程。
关键的异同就是
1 java api层面上看,一个事件就绪 是通过轮询的方式还是通过回调的方式响应 以进行后续操作。
2 nio中获得读写事件就绪后进行的读写操作是在用户线程中做的,会阻塞当前线程。而aio 的读写操作是内核中做的,并通过回调通知用户线程。 读操作是指把内核缓冲区的数据读到用户线程。