NIO 简单例子


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Created by lsy
 * on 2020/1/13 16:13.
 */
public class MultipleTimeClient implements Runnable {
    private SocketChannel socketChannel;
    private Selector selector;
    private volatile boolean stop = false;
    private int port;

    public MultipleTimeClient(int port) {
        this.port = port;
        try {
            socketChannel = SocketChannel.open();
            selector = Selector.open();
            socketChannel.configureBlocking(false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            // 处理连接
            boolean connect = socketChannel.connect(new InetSocketAddress("127.0.0.1", port));
            if (connect) {
                // 对读事件设置感兴趣
                socketChannel.register(selector, SelectionKey.OP_READ);
                // 连接上了,开始写入数据
                doWrite(socketChannel);
            } else {
                doConnect();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        while (!stop) {
            // 连上了,处理读出来的东西
            try {
                selector.select();
                Set selectionKeys = selector.selectedKeys();
                Iterator iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    handleInput(key);
                }
            } catch (IOException e) {
                e.printStackTrace();
                stop = true;
            }
        }
        if (selector != null) {
            try {
                selector.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void handleInput(SelectionKey key) {
        if (key.isConnectable()) {
            try {
                if (socketChannel.finishConnect()) {
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    doWrite(socketChannel);
                } else {
                    System.out.println("client cant connet to server " + port);
                    System.exit(1);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // 处理了读,记得处理连接啊
        if (key.isReadable()) {
            SocketChannel channel = (SocketChannel) key.channel();
            try {
                if (channel.finishConnect()) {
                    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);
                    int size = channel.read(byteBuffer);
                    if (size > 0) {
                        byteBuffer.flip(); // 和下面那句顺序不可以乱的
                        byte[] bytes = new byte[byteBuffer.remaining()];
                        byteBuffer.get(bytes);
                        String s = new String(bytes, "UTF-8");
                        System.out.println("client receive : " + s);
                        try {
                            TimeUnit.SECONDS.sleep(2);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        doWrite(socketChannel);
                    } else if (size < 0) {
                        key.cancel();
                        channel.close();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                stop = true;
            }
        }

    }

    private void doWrite(SocketChannel socketChannel) {
        String message = "time";
        ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
        try {
            socketChannel.write(buffer);
            if (!buffer.hasRemaining()) {
                System.out.println("send to server success");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void doConnect() {
        // 本质就是发送一个链接位置的event
        try {
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
        } catch (ClosedChannelException e) {
            e.printStackTrace();
        }
    }
}

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.Date;
import java.util.Iterator;
import java.util.Set;

/**
 * Created by lsy
 * on 2020/1/13 15:29.
 */
public class MultipleTimeServer implements Runnable {
    private ServerSocketChannel serverSocketChannel;
    private Selector selector;
    private volatile boolean stop = false;

    public MultipleTimeServer(int port) {
        try {
            serverSocketChannel = ServerSocketChannel.open();
            selector = Selector.open();
            // 设置非阻塞模式
            serverSocketChannel.configureBlocking(false);
            // 绑定端口
            serverSocketChannel.bind(new InetSocketAddress("127.0.0.1", port));
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("TimeServer start in port : " + port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        while (!stop) {
            try {
                selector.select();
                Set selectionKeys = selector.selectedKeys();
                Iterator iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    if (key.isAcceptable()) {
                        // 链接处理
                        handleAccept(key);
                    } else if (key.isReadable()) {
                        // 读处理
                        handleRead(key);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void handleRead(SelectionKey key) {
        SocketChannel channel = (SocketChannel) key.channel();
        // 开始读取
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        try {
            int size = channel.read(byteBuffer);
            if (size > 0) {
                // 读取到了数据
                byteBuffer.flip(); // 这句很重要啊,设置游标,不然get获取不了数据
                byte[] bytes = new byte[byteBuffer.remaining()];
                byteBuffer.get(bytes);
                String request = new String(bytes, "UTF-8");
                System.out.println("server receive order" + request);
                String curr = "time".equals(request) ? new Date().toString() : "bad order";
                // 回写当前时间
                doWrite(channel, curr);
            } else if (size < 0) {
                // 等于-1代表关闭了链接
                key.cancel();
                serverSocketChannel.close();
            } else {
                // 没有数据,正常情况,抛弃处理
            }
        } catch (IOException e) {
            e.printStackTrace();
            // 读发生异常,关闭channel
            try {
                channel.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    private void doWrite(SocketChannel channel, String curr) {
        ByteBuffer writeBuffer = ByteBuffer.wrap(curr.getBytes());
        try {
            channel.write(writeBuffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void handleAccept(SelectionKey key) {
        ServerSocketChannel channel = (ServerSocketChannel) key.channel();
        // 使用accept获得SocketChannel
        try {
            SocketChannel socketChannel = channel.accept();
            socketChannel.configureBlocking(false);
            // 并且注册到多路复用器
            socketChannel.register(selector, SelectionKey.OP_READ);
            System.out.println("server handle accept event");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

你可能感兴趣的:(原理理解)