服务器端
编写NIO服务端:
1、创建 SeverSockerChannel 对象
2、将 ServerSocketChannel 绑定到本机端口
3、将 ServerSocketChannel 设置为非阻塞模式
4、创建 Selector 选择器
5、将 ServerSocketChannel 注册到 Selector 选择器上并监听 SelectionKey.OP_ACCEPT 连接事件
6、轮询 selector 选择器,直到有事件准备就绪
7、对准备就绪的事件进行处理
public class NioServer {
public void start() throws IOException {
// 1.创建Selector
Selector selector = Selector.open();
// 2.创建ServerSocketChannel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 3.绑定本地端口
serverSocketChannel.socket().bind(new InetSocketAddress(10000));
// 4.设置非阻塞模式
serverSocketChannel.configureBlocking(false);
// 5.将serverSocketChannel注册到Selector,并监听连接事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
// 6.循环监听并处理事件
while (true) {
// 阻塞方法:获取已经就绪的事件
int readyChannels = selector.select();
// 没有准备就绪的事件,跳过本轮循环
if (readyChannels == 0) {
continue;
}
// 已经就绪的channel集合
Set<SelectionKey> selectionKeys = selector.selectedKeys();
// 获取迭代器
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
// 获取一个selectKey实例
SelectionKey selectionKey = iterator.next();
// 移除selectKey实例,避免多次处理
iterator.remove();
// 7.根据就绪状态调用相应的处理逻辑
// 连接事件就绪
if (selectionKey.isAcceptable()) {
acceptHandler(serverSocketChannel, selector);
}
// 可读事件就绪
if (selectionKey.isReadable()) {
readHandler(selectionKey, selector);
}
}
}
}
private void acceptHandler(ServerSocketChannel serverSocketChannel, Selector selector) throws IOException {
// 获取相应客户端的SocketChannel
SocketChannel socketChannel = serverSocketChannel.accept();
// 将socketChannel设置为非阻塞模式
socketChannel.configureBlocking(false);
// 将socketChannel注册到selector上,监听可读事件
socketChannel.register(selector, SelectionKey.OP_READ);
// 回送客户端消息
socketChannel.write(StandardCharsets.UTF_8.encode("你与聊天室其他人都不是朋友关系,请注意隐私安全!"));
}
private void readHandler(SelectionKey selectionKey, Selector selector) throws IOException {
// 从SelectionKey中获取到已经就绪的channel
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
// 创建Buffer
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
// 循环读取客户端信息
StringBuilder read = new StringBuilder();
while (socketChannel.read(byteBuffer) > 0) {
// 切换为读模式
byteBuffer.flip();
// 进行读取
read.append(StandardCharsets.UTF_8.decode(byteBuffer));
// 清空缓冲区
byteBuffer.clear();
}
System.out.println(read);
// 将客户端发送的请求信息,广播给其他客户端
// Selector.keys():获取所有注册的SelectionKey
for (SelectionKey key : selector.keys()) {
// 获取注册在select中的通道
SelectableChannel channel = key.channel();
// 如果为socketChannel
if (channel instanceof SocketChannel && channel != socketChannel) {
// 向其他客户端发送此客户端发送的消息
((SocketChannel) channel).write(StandardCharsets.UTF_8.encode(read.toString()));
}
}
}
public static void main(String[] args) throws IOException {
NioServer nioServer = new NioServer();
nioServer.start();
}
}
客户端
编写NIO客户端:
1、创建 SocketChannel 对象
2、设置当前客户端为非阻塞
3、连接远程服务器
4、创建 Selector 对象
5、将 SocketChannel 注册到 Selector 对象,并监听 SelectionKey.OP_READ 事件
6、轮询
public class NioClient {
private SocketChannel socketChannel;
public NioClient(String host, Integer port) {
try {
// 1.创建SocketChannel
socketChannel = SocketChannel.open();
// 2.连接到服务端
socketChannel.socket().connect(new InetSocketAddress(host, port));
// 3.设置到非阻塞模式
socketChannel.configureBlocking(false);
} catch (IOException e) {
e.printStackTrace();
}
}
public void send(String msg) throws IOException {
socketChannel.write(StandardCharsets.UTF_8.encode(msg));
}
public void receive() {
new Thread(() -> {
try {
Selector selector = Selector.open();
socketChannel.register(selector, SelectionKey.OP_READ);
while (true) {
int counts = selector.select();
if (counts == 0) {
continue;
}
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
// 获取SelectionKey
SelectionKey selectionKey = iterator.next();
// 删除已经处理的SelectionKey,避免重复处理
iterator.remove();
// 由于只绑定了一个SocketChannel且只监听OP_READ事件
if (selectionKey.isReadable()) {
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
while (socketChannel.read(byteBuffer) > 0) {
// 将byteBuffer切换为读模式
byteBuffer.flip();
// 控制台打印服务端消息
System.out.println(StandardCharsets.UTF_8.decode(byteBuffer));
// 清空byteBuffer
byteBuffer.clear();
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
public static void main(String[] args) {
NioClient nioClient = new NioClient("127.0.0.1", 10000);
// 客户端接受消息
nioClient.receive();
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("请输入要发送的信息:");
String msg = scanner.nextLine();
if ("close".equalsIgnoreCase(msg)) break;
try {
nioClient.send(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}