接下来进行一个实战例子,用NIO实现一个多人运动版本的聊天室。
服务端代码:
public class GroupChatServer {
private Selector selector;
private ServerSocketChannel serverSocketChannel;
public static final int PORT = 6667;
public GroupChatServer() { try { this.selector = Selector.open(); this.serverSocketChannel = ServerSocketChannel.open(); this.serverSocketChannel.bind(new InetSocketAddress("127.0.0.1", PORT)); serverSocketChannel.configureBlocking(false); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); } catch (Exception e) { e.printStackTrace(); } }
public void listen() { try { while (true) { int count = selector.select(2000); if (count > 0) { Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> it = selectionKeys.iterator(); while (it.hasNext()) { SelectionKey key = it.next(); if (key.isAcceptable()) { SocketChannel socketChannel = serverSocketChannel.accept(); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); System.out.println(socketChannel.getRemoteAddress() + "上线了~"); } if (key.isReadable()) { readData(key); } it.remove(); } } else { System.out.println("等待..."); } } } catch (Exception e) { e.printStackTrace(); } }
private void readData(SelectionKey selectionKey) { SocketChannel socketChannel = null; try { socketChannel = (SocketChannel) selectionKey.channel(); ByteBuffer byteBuffer = ByteBuffer.allocate(1024); int count = socketChannel.read(byteBuffer); if (count > 0) { String msg = new String(byteBuffer.array()); System.out.println("from 客户端:" + msg); notifyAllClient(msg, socketChannel); } } catch (Exception e) { try { System.out.println(socketChannel.getRemoteAddress() + "离线了..."); selectionKey.cancel(); socketChannel.close(); } catch (IOException e1) { e1.printStackTrace(); } } }
private void notifyAllClient(String msg, SocketChannel noNotifyChannel) throws Exception { System.out.println("服务器转发消息~"); for (SelectionKey selectionKey : selector.keys()) { Channel channel = selectionKey.channel(); if (channel instanceof SocketChannel && channel != noNotifyChannel) { SocketChannel socketChannel = (SocketChannel) channel; ByteBuffer byteBuffer = ByteBuffer.wrap(msg.getBytes()); socketChannel.write(byteBuffer); } } }
public static void main(String[] args) throws Exception { GroupChatServer chatServer = new GroupChatServer(); chatServer.listen(); } }
|
客户端代码:
public class GroupChatClinet {
private Selector selector;
private SocketChannel socketChannel;
private String userName;
public GroupChatClinet() { try { this.selector = Selector.open(); socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", GroupChatServer.PORT)); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); userName = socketChannel.getLocalAddress().toString().substring(1); System.out.println(userName + " is ok~"); } catch (Exception e) { e.printStackTrace(); } }
private void sendMsg(String msg) { msg = userName + "说:" + msg; try { socketChannel.write(ByteBuffer.wrap(msg.getBytes())); } catch (Exception e) { e.printStackTrace(); } }
private void readMsg() { try { int count = selector.select(); if (count > 0) { Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey selectionKey = iterator.next(); if (selectionKey.isReadable()) { SocketChannel channel = (SocketChannel) selectionKey.channel(); ByteBuffer byteBuffer = ByteBuffer.allocate(1024); channel.read(byteBuffer); System.out.println(new String(byteBuffer.array())); } iterator.remove(); } } } catch (Exception e) { e.printStackTrace(); } }
public static void main(String[] args) throws Exception { GroupChatClinet chatClinet = new GroupChatClinet(); new Thread(() -> { while (true) { chatClinet.readMsg(); try { Thread.sleep(3000); } catch (Exception e) { e.printStackTrace(); } } }).start(); Scanner scanner = new Scanner(System.in); while (scanner.hasNextLine()) { String msg = scanner.nextLine(); chatClinet.sendMsg(msg); } } }
|
先启动服务端的main方法,再启动两个客户端的main方法:
然后使用两个客户端开始聊天了~