技术栈

2019-05-11——Java NIO Socket

2019-05-13  本文已影响0人  烟雨乱平生

NIO的出现使得传统的Socket的通讯发生了巨大的改变。

NIO本质就是避免原始的TCP建立连接使用的3次握手的操作,减少网络开销。

NIO是非阻塞的

相比于传统的阻塞型IO,NIO是非阻塞的,所以对于服务端有如下做法:

/*使用NIO非阻塞处理socket请求*/
public static void s5() throws IOException {
    ExecutorService threadPool = new ThreadPoolExecutor(10,50,60, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.configureBlocking(false);
    serverSocketChannel.bind(new InetSocketAddress(9999));
    while (true){
        System.out.println("等待客户端接入...");
        SocketChannel socketChannel = serverSocketChannel.accept();
        if(socketChannel==null){
            continue;
        }
        threadPool.execute(()->{
            try {
                clientJoin();
                read(socketChannel);
                socketChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }
}

private static void read(SocketChannel socketChannel) throws IOException {
    StringBuilder content = new StringBuilder();
    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
    while(socketChannel.read(byteBuffer)!=-1){
        byteBuffer.flip();
        while (byteBuffer.hasRemaining()){
            byte[] data = new byte[byteBuffer.remaining()];
            byteBuffer.get(data);
            content.append(new String(data,0,data.length));
        }
        byteBuffer.clear();
    }
    System.out.println(content.toString());
}

当然也可以使用著名的Reactoer模式

服务端

/*Reactor模型*/
public static void s6() throws IOException {
    Selector selector = Selector.open();
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.configureBlocking(false);
    serverSocketChannel.bind(new InetSocketAddress(9999));
    serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    while (selector.select()>0){
        Set<SelectionKey> selectionKeys = selector.selectedKeys();
        Iterator<SelectionKey> iterator = selectionKeys.iterator();
        while (iterator.hasNext()){
            SelectionKey selectionKey = iterator.next();
            if (selectionKey.isConnectable()){
                onConnection(selectionKey);
            }else if(selectionKey.isAcceptable()){
                onAccept(selectionKey);
            }else if(selectionKey.isReadable()){
                onRead(selectionKey);
            }else if(selectionKey.isWritable()){
                onWrite(selectionKey);
            }
            iterator.remove();
        }
    }
}

private static void onWrite(SelectionKey selectionKey) throws IOException {
    System.out.println("写就绪");
    SocketChannel channel = (SocketChannel) selectionKey.channel();
    write(channel);
    channel.close();
}

private static void onRead(SelectionKey selectionKey) throws IOException {
    System.out.println("读就绪");
    SocketChannel channel = (SocketChannel) selectionKey.channel();
    read(channel);
    channel.register(selectionKey.selector(),SelectionKey.OP_WRITE);
}

private static void onAccept(SelectionKey selectionKey) throws IOException {
    System.out.println("接收数据就绪");
    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
    SocketChannel socketChannel = serverSocketChannel.accept();
    Selector selector = selectionKey.selector();
    socketChannel.configureBlocking(false);
    socketChannel.register(selector,SelectionKey.OP_READ);
}

private static void onConnection(SelectionKey selectionKey) {
    System.out.println("链接就绪");
}

private static void read(SocketChannel socketChannel) throws IOException {
    StringBuilder content = new StringBuilder();
    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
    while(socketChannel.read(byteBuffer)!=-1){
        byteBuffer.flip();
        while (byteBuffer.hasRemaining()){
            byte[] data = new byte[byteBuffer.remaining()];
            byteBuffer.get(data);
            content.append(new String(data,0,data.length));
        }
        byteBuffer.clear();
    }
    System.out.println(content.toString());
}

private static void write(SocketChannel socketChannel) throws IOException {
    byte[] data = "这是服务端,正在使用Channel".getBytes();
    ByteBuffer byteBuffer = ByteBuffer.allocate(data.length);
    byteBuffer.put(data);
    byteBuffer.flip();
    socketChannel.write(byteBuffer);
}
上一篇下一篇

猜你喜欢

热点阅读