一、原理图
NIO 非阻塞 网络编程相关的(Selector、SelectionKey、ServerScoketChannel 和 SocketChannel) 关系梳理图:
说明:
- 当客户端连接时,会通过 ServerSocketChannel 得到 SocketChannel
- Selector 进行监听 select 方法, 返回有事件发生的通道的个数
- 将 serverSocketChannel 注册到Selector上,register(selector, SelectionKey),一个 selector 上可以注册多个 serverSocketChannel
- 注册后返回一个 SelectionKey, 会和该 Selector 关联(集合)
- 监听 SelectionKey 进一步得到各个 SelectionKey (有事件发生)
- 通过 SelectionKey 反向获取 SocketChannel , 方法 channel()
- 可以通过得到的 channel , 完成业务处理
代码实例:
https://github.com/Wells-Lee/netty-demo/tree/master/src/main/java/com/wells/demo/nio/non/blocking
二、类说明
2.1、SelectionKey
SelectionKey,表示 Selector 和网络通道的注册关系, 共四种:
- int OP_ACCEPT:有新的网络连接可以 accept,值为 16
- int OP_CONNECT:代表连接已经建立,值为 8
- int OP_READ:代表读操作,值为 1
- int OP_WRITE:代表写操作,值为 4
源码中:
public static final int OP_READ = 1 << 0;
public static final int OP_WRITE = 1 << 2;
public static final int OP_CONNECT = 1 << 3;
public static final int OP_ACCEPT = 1 << 4;
SelectionKey相关方法:
public abstract Selector selector(); // 得到与之关联的 Selector 对象
public abstract SelectableChannel channel(); // 得到与之关联的 channel
public abstract SelectionKey interestOps(int ops); // 设置或者改变监听事件
public final boolean isReadable(); // 是否为读事件
public final boolean isWritable(); // 是否为写事件
public final boolean isConnectable(); // 是否为连接事件
public final boolean isAcceptable(); // 是否为接受事件
public final Object attachment(); // 得到与之关联的共享数据
2.2、ServerSocketChannel
ServerSocketChannel 在服务器端监听客户端 Socket 的连接;
相关方法:
public static ServerSocketChannel open(); // 得到一个 ServerSocketChannel 连接
public final ServerSocketChannel bind(SocketAddress local); // 设置服务器ip、端口
public abstract SocketChannel accept(); // 接收一个客户端连接
public final SelectionKey register(Selector sel, int ops); // 注册一个选择器并选择监听事件
public final SelectableChannel configureBlocking(boolean block); // 设置是否阻塞
2.3、SocketChannel
SocketChannel,网络 IO 通道,具体负责进行读写操作。NIO 把缓冲区的数据写入通道,或者把通道里的数据读到缓冲区。
相关方法:
public static SocketChannel open(SocketAddress remote); // 得到一个 SocketChannel 连接
public final SelectableChannel configureBlocking(boolean block); // 社渚是否阻塞
public abstract boolean isConnected(); // 连接服务器
public abstract boolean finishConnect(); // 如果上面的方法连接失败,接下来就要通过该方法连接
public final SelectionKey register(Selector sel, int ops); // 注册一个选择器,并设置监听事件
public abstract int write(ByteBuffer src); // 写数据
public final long read(ByteBuffer[] dsts); // 读数据
public final void close(); // 关闭连接
三、实例练习
实例要求:
- 编写一个 NIO 群聊系统,实现服务器端和客户端之间的数据简单通讯(非阻塞)
- 实现多人群聊
服务器端:可以监测用户上线,离线,并实现消息转发功能
客户端:通过channel可以无阻塞发送消息给其它所有用户,同时可以接受其它用户发送的消息(有服务器转发得到)
代码实例:
https://github.com/Wells-Lee/netty-demo/tree/master/src/main/java/com/wells/demo/nio/groupchat
<br />
<br />
<br />
<br />
<br />