|
@@ -0,0 +1,109 @@
|
|
|
+package com.sf.javase.io.socket.chat;
|
|
|
+
|
|
|
+import lombok.SneakyThrows;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.net.InetSocketAddress;
|
|
|
+import java.nio.ByteBuffer;
|
|
|
+import java.nio.channels.*;
|
|
|
+import java.util.Iterator;
|
|
|
+import java.util.Set;
|
|
|
+
|
|
|
+// 服务端
|
|
|
+public class ChatServer {
|
|
|
+
|
|
|
+ // 服务端通道
|
|
|
+ private ServerSocketChannel serverSocketChannel;
|
|
|
+ private Selector selector;
|
|
|
+
|
|
|
+ @SneakyThrows
|
|
|
+ public ChatServer(int port) {
|
|
|
+ selector = Selector.open();
|
|
|
+
|
|
|
+ serverSocketChannel = ServerSocketChannel.open();
|
|
|
+ serverSocketChannel.socket().bind(new InetSocketAddress(port));
|
|
|
+ serverSocketChannel.configureBlocking(false);
|
|
|
+ // 服务端 要接收客户端连接事件
|
|
|
+ serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
|
|
|
+ }
|
|
|
+
|
|
|
+ @SneakyThrows
|
|
|
+ public void listenClient() {
|
|
|
+ System.out.println("服务端启动监听");
|
|
|
+ while (true) {
|
|
|
+ int select = selector.select();
|
|
|
+ if (select == 0) continue;
|
|
|
+ Set<SelectionKey> selectionKeys = selector.selectedKeys();
|
|
|
+ Iterator<SelectionKey> iterator = selectionKeys.iterator();
|
|
|
+ while (iterator.hasNext()) {
|
|
|
+ SelectionKey key = iterator.next();
|
|
|
+ iterator.remove();
|
|
|
+ if (key.isAcceptable()) {
|
|
|
+ SocketChannel clientChannel = serverSocketChannel.accept();
|
|
|
+ clientChannel.configureBlocking(false);
|
|
|
+ clientChannel.register(selector, SelectionKey.OP_READ);
|
|
|
+ // getRemoteAddress() 是客户端的ip地址+端口号
|
|
|
+ System.out.println("用户" + clientChannel.getRemoteAddress() + "上线了");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (key.isReadable()) {
|
|
|
+ readData(key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void readData(SelectionKey key) {
|
|
|
+ // 如果客户端建立连接之后 服务关闭了
|
|
|
+ // 此时SelectionKey存在 但无法获取通道
|
|
|
+ SocketChannel channel = null;
|
|
|
+ try {
|
|
|
+ channel = (SocketChannel) key.channel();
|
|
|
+ ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
|
|
|
+ int read = channel.read(byteBuffer);
|
|
|
+ if (read > 0) {
|
|
|
+ String msg = new String(byteBuffer.array(), 0, read);
|
|
|
+ // 打印消息 及消息来源
|
|
|
+ System.out.println(msg + " from " + channel.socket().getRemoteSocketAddress());
|
|
|
+
|
|
|
+ // 再将消息转发给其他客户端(排除发送数据的客户端)
|
|
|
+ sendToOthers(msg, channel);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 用户下线了
|
|
|
+ System.out.println("用户" + channel.socket().getRemoteSocketAddress() + "下线了");
|
|
|
+ // 注销注册关系
|
|
|
+ key.cancel();
|
|
|
+ try {
|
|
|
+ channel.close();
|
|
|
+ } catch (IOException ex) {
|
|
|
+ throw new RuntimeException(ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 发送给其他客户端
|
|
|
+ // 接收参数为 要发送的消息 和 发送消息的自身客户端
|
|
|
+ @SneakyThrows
|
|
|
+ private void sendToOthers(String msg,SocketChannel selfChannel) {
|
|
|
+ // 获取所有的通道 可以找到所有的在线用户
|
|
|
+ Set<SelectionKey> keys = selector.keys();
|
|
|
+ for (SelectionKey key : keys) {
|
|
|
+ SelectableChannel channel = key.channel();
|
|
|
+ // SocketChannel才是客户端 找到所有客户端 排除发送消息的客户端
|
|
|
+ if (channel instanceof SocketChannel && channel != selfChannel) {
|
|
|
+ SocketChannel socketChannel = (SocketChannel) channel;
|
|
|
+ ByteBuffer byteBuffer = ByteBuffer.wrap(msg.getBytes());
|
|
|
+ socketChannel.write(byteBuffer);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void main(String[] args) {
|
|
|
+ ChatServer server = new ChatServer(6666);
|
|
|
+ // 监听客户端
|
|
|
+ server.listenClient();
|
|
|
+ }
|
|
|
+}
|