From fb31a4739c8eed1e83f20ba5f6acb50cf032af4b Mon Sep 17 00:00:00 2001 From: ehlxr Date: Sun, 24 Jan 2021 12:38:01 +0800 Subject: [PATCH] add io demo --- .../java/io/github/ehlxr/io/BioServer.java | 95 +++++++++++++++++++ src/main/java/io/github/ehlxr/io/Client.java | 59 ++++++++++++ .../io/github/ehlxr/io/SelectorServer.java | 92 ++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 src/main/java/io/github/ehlxr/io/BioServer.java create mode 100644 src/main/java/io/github/ehlxr/io/Client.java create mode 100644 src/main/java/io/github/ehlxr/io/SelectorServer.java diff --git a/src/main/java/io/github/ehlxr/io/BioServer.java b/src/main/java/io/github/ehlxr/io/BioServer.java new file mode 100644 index 0000000..27b9595 --- /dev/null +++ b/src/main/java/io/github/ehlxr/io/BioServer.java @@ -0,0 +1,95 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2020 xrv + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package io.github.ehlxr.io; + +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.charset.StandardCharsets; + +/** + * @author ehlxr + * @since 2021-01-23 20:07. + */ +public class BioServer { + public static void main(String[] args) throws IOException { + ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); + + // 监听 8080 端口进来的 TCP 链接 + serverSocketChannel.socket().bind(new InetSocketAddress(8080)); + + //noinspection InfiniteLoopStatement + while (true) { + // 这里会阻塞,直到有一个请求的连接进来 + SocketChannel socketChannel = serverSocketChannel.accept(); + + // 开启一个新的线程来处理这个请求,然后在 while 循环中继续监听 8080 端口 + SocketHandler handler = new SocketHandler(socketChannel); + //noinspection AlibabaAvoidManuallyCreateThread + new Thread(handler).start(); + } + } + + static class SocketHandler implements Runnable { + private final SocketChannel socketChannel; + + public SocketHandler(SocketChannel socketChannel) { + this.socketChannel = socketChannel; + } + + @Override + public void run() { + + ByteBuffer buffer = ByteBuffer.allocate(1024); + try { + // 将请求数据读入 Buffer 中 + int num; + while ((num = socketChannel.read(buffer)) > 0) { + // 读取 Buffer 内容之前先 flip 一下 + buffer.flip(); + + // 提取 Buffer 中的数据 + byte[] bytes = new byte[num]; + buffer.get(bytes); + + String re = new String(bytes, StandardCharsets.UTF_8); + System.out.println("收到请求:" + re); + + // 回应客户端 + ByteBuffer writeBuffer = ByteBuffer.wrap(("我已经收到你的请求,你的请求内容是:" + re).getBytes()); + socketChannel.write(writeBuffer); + + buffer.clear(); + } + } catch (IOException e) { + IOUtils.closeQuietly(socketChannel); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/io/github/ehlxr/io/Client.java b/src/main/java/io/github/ehlxr/io/Client.java new file mode 100644 index 0000000..34a6ee8 --- /dev/null +++ b/src/main/java/io/github/ehlxr/io/Client.java @@ -0,0 +1,59 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2020 xrv + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package io.github.ehlxr.io; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; +import java.nio.charset.StandardCharsets; + +/** + * @author ehlxr + * @since 2021-01-23 20:09. + */ +public class Client { + public static void main(String[] args) throws IOException { + SocketChannel socketChannel = SocketChannel.open(); + socketChannel.connect(new InetSocketAddress("localhost", 8080)); + + // 发送请求 + ByteBuffer buffer = ByteBuffer.wrap("1234567890".getBytes()); + socketChannel.write(buffer); + + // 读取响应 + ByteBuffer readBuffer = ByteBuffer.allocate(1024); + int num; + if ((num = socketChannel.read(readBuffer)) > 0) { + readBuffer.flip(); + + byte[] re = new byte[num]; + readBuffer.get(re); + + String result = new String(re, StandardCharsets.UTF_8); + System.out.println("返回值: " + result); + } + } +} diff --git a/src/main/java/io/github/ehlxr/io/SelectorServer.java b/src/main/java/io/github/ehlxr/io/SelectorServer.java new file mode 100644 index 0000000..fa9d95e --- /dev/null +++ b/src/main/java/io/github/ehlxr/io/SelectorServer.java @@ -0,0 +1,92 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2020 xrv + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package io.github.ehlxr.io; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.util.Iterator; +import java.util.Set; + +/** + * @author ehlxr + * @since 2021-01-23 20:18. + */ +public class SelectorServer { + public static void main(String[] args) throws IOException { + Selector selector = Selector.open(); + + ServerSocketChannel server = ServerSocketChannel.open(); + server.socket().bind(new InetSocketAddress(8080)); + + // 将其注册到 Selector 中,监听 OP_ACCEPT 事件 + server.configureBlocking(false); + server.register(selector, SelectionKey.OP_ACCEPT); + + //noinspection InfiniteLoopStatement + while (true) { + int readyChannels = selector.select(); + if (readyChannels == 0) { + continue; + } + Set readyKeys = selector.selectedKeys(); + // 遍历 + Iterator iterator = readyKeys.iterator(); + while (iterator.hasNext()) { + SelectionKey key = iterator.next(); + iterator.remove(); + + if (key.isAcceptable()) { + // 有已经接受的新的到服务端的连接 + SocketChannel socketChannel = server.accept(); + + // 有新的连接并不代表这个通道就有数据, + // 这里将这个新的 SocketChannel 注册到 Selector,监听 OP_READ 事件,等待数据 + socketChannel.configureBlocking(false); + socketChannel.register(selector, SelectionKey.OP_READ); + } else if (key.isReadable()) { + // 有数据可读 + // 上面一个 if 分支中注册了监听 OP_READ 事件的 SocketChannel + SocketChannel socketChannel = (SocketChannel) key.channel(); + ByteBuffer readBuffer = ByteBuffer.allocate(1024); + int num = socketChannel.read(readBuffer); + if (num > 0) { + // 处理进来的数据... + System.out.println("收到数据:" + new String(readBuffer.array()).trim()); + ByteBuffer buffer = ByteBuffer.wrap("返回给客户端的数据...".getBytes()); + socketChannel.write(buffer); + } else if (num == -1) { + // -1 代表连接已经关闭 + socketChannel.close(); + } + } + } + } + } +} \ No newline at end of file