概述
回显服务器是指接收到客户端的数据,原封不动的返回给客户端
小提示 在阅读这里之前,希望先看一个视频和相关API的介绍,API的介绍不是很详细,当然也可以遇到不知道的API在百度/Google搜索 视频:https://www.bilibili.com/video/av57390893?t=5655 相关API: https://lyhcc.github.io/post/f2d80d11.html#more
源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 import java.io.IOException;import java.net.InetSocketAddress;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.util.Iterator;public class NIOServer { public static void main (String[] args) throws IOException { Selector selector = Selector.open(); ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false ); serverSocketChannel.socket().bind(new InetSocketAddress("127.0.0.1" ,12122 )); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); while (true ) { if (selector.select() == 0 ) { System.out.println("Nothing to do!" ); continue ; } Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); if (key.isAcceptable()) { SocketChannel channel = serverSocketChannel.accept(); channel.configureBlocking(false ); SelectionKey connkey = channel.register(selector, SelectionKey.OP_READ); NIOConnection conn = new NIOConnection(connkey); connkey.attach(conn); } if (key.isValid() && key.isReadable()) { NIOConnection conn = (NIOConnection) key.attachment(); conn.handleRead(); } if (key.isValid() && key.isWritable()) { NIOConnection conn = (NIOConnection) key.attachment(); conn.handleWrite(); } } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.SocketChannel;import java.nio.charset.Charset;public class NIOConnection { private SelectionKey key; private SocketChannel channel; private ByteBuffer buffer; public NIOConnection (SelectionKey key) { this .buffer = ByteBuffer.allocate(1024 ); this .key = key; this .channel = (SocketChannel) key.channel(); } public void handleRead () throws IOException { int byteRead = channel.read(buffer); if (byteRead == -1 ) { channel.close(); }else { key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); } } public void handleWrite () throws IOException { buffer.flip(); System.out.println("收到的数据:" + Charset.forName("UTF-8" ).decode(buffer).toString()); channel.write(buffer); if (!buffer.hasRemaining()) { key.interestOps(SelectionKey.OP_READ); } buffer.compact(); }
注意:NIO是没有专门的客户端的,你可以使用Socket进行连接,也可以使用telnet进行连接
Selector的使用步骤
创建一个Selector实例:
将该实例注册到各种通道,指定每个通道上感兴趣的I/O操作;
重复执行(选择器循环):
调用一种select()方法;
获取已选键集;
对于已选键集中的每-一个键:
将已选键从键集中移除;
获取信道,并从键中获取附件(如果需要);
确定准备就绪的操作并执行;对于accept操作获得的SocketChannel对象,需将信道设置为非阻塞模式,并将其注册到选择器中;
根据需要,修改键的兴趣操作集。
错误总结
这里的connkey用错会报错Exception in thread "main" java.lang.ClassCastException: sun.nio.ch.ServerSocketChannelImpl cannot be cast to java.nio.channels.SocketChannel