服务器端
编写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.创建SelectorSelector selector = Selector.open();// 2.创建ServerSocketChannelServerSocketChannel 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 {// 获取相应客户端的SocketChannelSocketChannel 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中获取到已经就绪的channelSocketChannel socketChannel = (SocketChannel) selectionKey.channel();// 创建BufferByteBuffer 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():获取所有注册的SelectionKeyfor (SelectionKey key : selector.keys()) {// 获取注册在select中的通道SelectableChannel channel = key.channel();// 如果为socketChannelif (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.创建SocketChannelsocketChannel = 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()) {// 获取SelectionKeySelectionKey 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));// 清空byteBufferbyteBuffer.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();}}}}
