实现NIO(实现Server和Client)

136 阅读1分钟

Server

serverSocketChannel用于ServerSocketChannel的建立和端口的绑定。
byteBuffer用于不同Channel之间的数据交互。
selector用于监听服务器各个Channel上数据的变化并做出响应。
构造函数调用了初始化ServerSocketChannel的操作,定义了listener方法监听Channel数据变化,解析客户端的数据并对客户端的请求做出响应。

public class MyServer {
    private int size = 1024;
    private ServerSocketChannel serverSocketChannel;
    private ByteBuffer byteBuffer;
    private Selector selector;
    private int remoteClientNum = 0;
    public MyServer(int port) {
        try {
            initChannel(port);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }
    }
    //Channel初始化
    public void initChannel (int port) throws IOException {
        serverSocketChannel = ServerSocketChannel.open();//打开
        serverSocketChannel.configureBlocking(false);//设置为非阻塞模式
        serverSocketChannel.bind(new InetSocketAddress(port));//绑定端口
        System.out.println("listener on port: " + port);
        selector = Selector.open();//选择注册通道
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        byteBuffer = ByteBuffer.allocate(size);//缓冲区大小
    }
    //监听器
    private void listener() throws Exception {
        while (true) {
            int n = selector.select();
            if (n == 0) {
                continue;
            }
            Iterator<SelectionKey> interator = 
                                    selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel channel = server.accept();
                    registerChannel (selector, channel, SelectionKey.OP_READ);
                    remoteClientNum++;
                    System.out.println("Online client num="+remoteClientNum);
                    write(channel,"hello client".getBytes());
                }
                if(key.isReadable()) {
                    read(key);
                }
                iterator.remove();
            }
        }
    }
    private void read(SelectionKey key) throws IOException {
        SocketChannel socketChannel = (SocketChannel) key.channel();
        int count;
        byteBuffer.clear();
        while ((count = socketChannel.read(byteBuffer)) > 0) {
            byteBuffer.flip();
            while (byteBuffer.hasRemaining()) {
                System.out.println((char)byteBuffer.get());
            }
            byteBuffer.clear;
        }
        if(count < 0) {
            socketChannel.close();
        }
    }
    private void write(SocketChannel channel,byte[] writeData) throws IOException {
        byteBuffer.clear();
        byteBuffer.put(writeData);
        byteBuffer.flip();
        channel.write(byteBuffer);
    }
    private void registerChannel(Selector selector, SocketChannel channel, int opRead) throws IOException {
        if(channel == null) {
            return;
        }
        channel.configureBlocking(false);
        channel.register(selector, opRead);
    }
    public static void main(String[] args) {
        try{
            MyServer myServer = new MyServer(9999);
            myServer.listener();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Client

connectServer用于和服务器建立连接,receive方法用于接收服务端发来的数据,send2Server用于向服务端发送数据。

public class MyClient {
    private int size = 1024;
    private ByteBuffer byteBuffer;
    private SocketChannel socketChannel;
    public void connectServer() throws IOException {
        socketChannel = socketChannel.open();
        socketChannel.connect(new InetSocketAddress("127.0.0.1", 9999));
        socketChannel.configureBlocking(false);
        byteBuffer = ByteBuffer.allocate(size);
        receive();
    }
    private void receive() throws IOException {
        while (true) {
            byteBuffer.clear();
            int count;
            while ((count = socketChannel.read(byteBuffer)) > 0) {
                byteBuffer.flip();
                while (byteBuffer.hasRemaining()) {
                    System.out.print((char)byteBuffer.get());
                }
                send2Server("say hi".getBytes());
                byteBuffer.clear();
            }
        }
    }
    private void send2Server(byte[] bytes) throws IOException {
        byteBuffer.clear();
        byteBuffer.put(bytes);
        byteBuffer.flip();
        socketChannel.write(byteBuffer);
    }
    public static void main(String[] args) throws IOException {
        new MyClient().connectServer();
    }
}