NIO 通信示例

在之前的三篇文章中介绍了 NIO 的相关知识:

下面根据 NIO 的相关知识,编写一个 NIO 服务端与客户端通信的一个完整的比较简单的例子。

程序的功能是客户端向服务器端发送 request time 请求,服务器接收到请求并验证正确后向客户端返回服务器时间。

服务器:

public class TimeServer {
    private static final String ORDER = "request time";
    private static final int DEFAULT_PORT = 8080;
    private static volatile boolean stop = false;
    private static Selector selector;

    public static void main(String[] args) throws IOException {
        new TimeServer().run();
    }

    /**
     * 启动服务器
     * @throws IOException
     */
    public void run() throws IOException {
        run(DEFAULT_PORT);
    }

    private void run(int port) throws IOException {
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);
        selector = Selector.open();
        ssc.register(selector, SelectionKey.OP_ACCEPT);
        ssc.bind(new InetSocketAddress(port));
        System.out.println("服务器已开启!");
        while (!stop) {
            selector.select(1000);
            Set<SelectionKey> keySet = selector.selectedKeys();
            Iterator<SelectionKey> it = keySet.iterator();
            while (it.hasNext()) {
                SelectionKey key = it.next();
                try {
                    response(key);
                } catch (IOException e) {
                    key.cancel();
                    key.channel().close();
                }
                it.remove();
            }
        }
    }

    /**
     * 接收客户端请求并返回相应内容
     * @param key
     * @throws IOException
     */
    private void response(SelectionKey key) throws IOException {
        if (key.isValid()) {
            if (key.isAcceptable()) {
                ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                SocketChannel sc = ssc.accept();
                sc.configureBlocking(false);
                sc.register(selector, SelectionKey.OP_READ);
            }
            if (key.isReadable()) {
                SocketChannel sc = (SocketChannel) key.channel();
                ByteBuffer toRead = ByteBuffer.allocate(1024);
                int number = sc.read(toRead);
                if (number > 0) {
                    toRead.flip();
                    byte[] msg = new byte[toRead.remaining()];
                    toRead.get(msg);
                    String order = new String(msg, "UTF-8");
                    System.out.println("接收请求:" + order);
                    String response;
                    if (ORDER.equalsIgnoreCase(order)) {
                        response = LocalDateTime.now().withNano(0).toString();
                        System.out.println("成功发送:" + response);
                    } else
                        response = "请求错误!";
                    ByteBuffer toWrite = ByteBuffer.allocate(response.length());
                    toWrite.put(response.getBytes());
                    toWrite.flip();
                    sc.write(toWrite);
                } else if (number < 0) {
                    key.cancel();
                    sc.close();
                }
            }
        }
    }

    /**
     * 停止服务器
     */
    private void stop() {
        stop = true;
    }
}

客户端:

public class TimeClient {
    private static final int DEFAULT_PORT = 8080;
    private static final String ORDER = "request time";
    private SocketChannel sc;
    private Selector selector;

    public static void main(String[] args) throws IOException {
        new TimeClient().run();
    }

    /**
     * 运行客户端
     * @throws IOException
     */
    public void run() throws IOException {
        sc = SocketChannel.open();
        sc.configureBlocking(false);
        selector = Selector.open();
        connect(InetAddress.getLocalHost(), DEFAULT_PORT);
        while (true) {
            selector.select(1000);
            Set<SelectionKey> keySet = selector.selectedKeys();
            Iterator<SelectionKey> it = keySet.iterator();
            while (it.hasNext()) {
                SelectionKey key = it.next();
                try {
                    request(key);
                } catch (IOException e) {
                    key.cancel();
                    key.channel().close();
                }
                it.remove();
            }
        }
    }

    /**
     * 与服务器连接
     * @param address 服务器地址
     * @param port    服务器端口
     * @throws IOException
     */
    public void connect(InetAddress address, int port) throws IOException {
        System.out.println("连接服务器中......");
        boolean connected = sc.connect(new InetSocketAddress(address, port));
        if (connected) {
            System.out.println("连接成功!");
            ByteBuffer toWrite = ByteBuffer.allocate(ORDER.length());
            toWrite.put(ORDER.getBytes());
            toWrite.flip();
            sc.write(toWrite);
            System.out.println("发送命令:" + ORDER);
        } else {
            sc.register(selector, SelectionKey.OP_CONNECT);
        }
    }

    /**
     * 向服务器发送请求
     * @param key
     * @throws IOException
     */
    public void request(SelectionKey key) throws IOException {
        if (key.isValid()) {
            SocketChannel channel = (SocketChannel) key.channel();
            channel.configureBlocking(false);
            if (key.isConnectable()) {
                try {
                    if (channel.finishConnect()) {
                        System.out.println("连接成功!");
                        channel.register(selector, SelectionKey.OP_READ);
                        ByteBuffer toWrite = ByteBuffer.allocate(ORDER.getBytes().length);
                        toWrite.put(ORDER.getBytes());
                        toWrite.flip();
                        channel.write(toWrite);
                        System.out.println("发送请求:" + ORDER);
                    }
                } catch (IOException e) {
                    System.out.println("连接失败!");
                    System.exit(1);
                }
            }
            if (key.isReadable()) {
                ByteBuffer toRead = ByteBuffer.allocate(1024);
                int number = channel.read(toRead);
                if (number > 0) {
                    toRead.flip();
                    byte[] msg = new byte[toRead.remaining()];
                    toRead.get(msg);
                    String response = new String(msg, "UTF-8");
                    System.out.println("返回时间:" + response);
                } else if (number < 0) {
                    key.cancel();
                    channel.close();
                }
            }
        }
    }
}

运行结果:

  • 服务器
服务器已开启!
接收请求:request time
成功发送:2017-11-24T21:35
  • 客户端
连接服务器中......
连接成功!
发送请求:request time
返回时间:2017-11-24T21:35

参考链接:

  • Netty权威指南

猜你喜欢

转载自blog.csdn.net/weixin_43320847/article/details/83241544
今日推荐