Netty之NIO

java.io最为核心的一个概念是流(stream),面向流的编程,在java中,一个流要么是输入流,要么是输出流。
java.nio中拥有三个核心概念,selector,channel和buffer,在Java.nio中我们是面向块(block)或是缓冲区(buffer)编程的,buffer本身就是一块内存,底层实现上,实际就是一个数组,数据的读写都是通过buffer来实现的。

除了数组外,buffer还提供了对于数据的结构化访问方式,并且可以追踪到系统的读写过程。
java中7中原生数据类型(除了boolean)都有各自的buffer类型,如IntBuffer,ByteBuffer和CharBuffer等。
channel指的是可以向其写入数据或者从中读取数据的对象,它类似java.io中的stream。
所有数据的读写都是通过buffer来进行的,永远不会出现数据直接向channel中写入数据的情况,或者直接从channel中读取数据。
与stream不同的是channel是双向的,一个流只可能是inputStream或者outputStream,

案例

package com.kkagr.nio;

import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class NioTest2 {
    public static void main(String[] args) throws Exception{
        FileInputStream fileInputStream = new FileInputStream("NioTest2.text");
        FileChannel fileChannel = fileInputStream.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(512);
        fileChannel.read(byteBuffer);
        byteBuffer.flip();
        while (byteBuffer.remaining()>0){
            byte b = byteBuffer.get();
            System.out.println("character:"+(char)b);
        }
        fileInputStream.close();

    }


}

在这里插入图片描述
在这里插入图片描述

package com.kkagr.nio;

import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class NioTest3 {

    public static void main(String[] args) throws Exception{
        FileOutputStream fileOutputStream = new FileOutputStream("NioTest3.txt");
        FileChannel fileChannel = fileOutputStream.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(512);
        byte[] messages = "hello world welcome,nihao".getBytes();
        for(int i = 0;i<messages.length;++i){
            byteBuffer.put(messages[i]);
        }
        byteBuffer.flip();
        fileChannel.write(byteBuffer);
        fileOutputStream.close();
    }
}

在这里插入图片描述

package com.kkagr.nio;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class NioTest4 {

    public static void main(String[] args) throws Exception{
        FileInputStream inputStream = new FileInputStream("NioTest2.text");
        FileOutputStream outputStream = new FileOutputStream("NioTest4.text");
        FileChannel inputChannel = inputStream.getChannel();
        FileChannel outputChannel = outputStream.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(2);
        while(true){
            byteBuffer.clear();
            int read = inputChannel.read(byteBuffer);
            System.out.println(read);
            if(-1 ==read){
                System.out.println("over");
                break;
            }
            byteBuffer.flip();
            outputChannel.write(byteBuffer);

        }
        inputChannel.close();
        outputChannel.close();

    }
}

在这里插入图片描述
等待数据制定字符数,然后回显

package com.kkagr.nio;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Arrays;

public class NioTest11 {
    public static void main(String[] args) throws Exception{
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        InetSocketAddress address = new InetSocketAddress(8899);
        serverSocketChannel.socket().bind(address);
        int messageLenth = 2+3+4;
        ByteBuffer[] byteBuffers = new ByteBuffer[3];
        byteBuffers[0] = ByteBuffer.allocate(2);
        byteBuffers[1] = ByteBuffer.allocate(3);
        byteBuffers[2] = ByteBuffer.allocate(4);
        SocketChannel socketChannel = serverSocketChannel.accept();
        while(true){
            int byteRead = 0;
            while(byteRead < messageLenth){
                long r = socketChannel.read(byteBuffers);
                byteRead +=r;
                System.out.println("byteRead:"+byteRead);
                Arrays.asList(byteBuffers).stream().
                        map(buffer ->"positin:"+buffer.position()+",limit"+buffer.limit()).
                        forEach(System.out::println);
            }
            Arrays.asList(byteBuffers).forEach(byteBuffer -> {
                byteBuffer.flip();
            });
            long byteWritten = 0;
            while (byteWritten < messageLenth){
                long r = socketChannel.write(byteBuffers);
                byteWritten+=r;
            }
            Arrays.asList(byteBuffers).forEach(byteBuffer -> {
                byteBuffer.clear();
            });
            System.out.println("bytesRead:"+byteRead+",byteWriteen:"+byteWritten+",messageLenth"+messageLenth);
        }
    }
}

在这里插入图片描述
selector特性,一个selector多个channel

package com.kkagr.nio;


import java.net.InetSocketAddress;
import java.net.ServerSocket;
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;

public class NioTest12 {

    public static void main(String[] args) throws Exception{
        int[] ports = new int[5];
        ports[0]=5000;
        ports[1]=5001;
        ports[2]=5002;
        ports[3]=5003;
        ports[4]=5004;

        Selector selector = Selector.open();

        for(int i =0 ;i< ports.length;i++){
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);
            ServerSocket serverSocket = serverSocketChannel.socket();
            InetSocketAddress address = new InetSocketAddress(ports[i]);
            serverSocket.bind(address);
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("监听端口:"+ports[i]);
        }

        while (true){
            int numbers = selector.select();
            System.out.println("numbers:"+numbers);
            Set<SelectionKey>   selectionKeys = selector.selectedKeys();
            System.out.println("selectionkeys:"+selectionKeys);
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while(iterator.hasNext()){
                SelectionKey selectionKey = iterator.next();
                if(selectionKey.isAcceptable()){
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector,SelectionKey.OP_READ);
                    iterator.remove();
                    System.out.println("获得客户端连接:"+socketChannel);
                }else if(selectionKey.isReadable()){
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                   int byteRead = 0;
                   while(true){
                       ByteBuffer byteBuffer = ByteBuffer.allocate(512);
                       byteBuffer.clear();
                       int read = socketChannel.read(byteBuffer);
                       if(read  <= 0){
                           break;
                       }
                       byteBuffer.flip();
                       socketChannel.write(byteBuffer);
                       byteRead+=read;
                   }
                    System.out.println("读取:"+byteRead+",来自:"+socketChannel);
                   iterator.remove();

                }
            }
        }
        
    }
}

在这里插入图片描述
在这里插入图片描述

使用nio进行多客户端聊天

package com.kkagr.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

public class NioServer {
    public static Map<String,SocketChannel> clientMap = new HashMap<>();
    public static void main(String[] args) throws Exception{
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        ServerSocket serverSocket = serverSocketChannel.socket();
        serverSocket.bind(new InetSocketAddress(8899));
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true){
            selector.select();
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            selectionKeys.forEach(selectionKey -> {
                final SocketChannel client;
                try {
                    if(selectionKey.isAcceptable()){
                        ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel();
                        client = server.accept();
                        client.configureBlocking(false);
                        client.register(selector,SelectionKey.OP_READ);
                        String key = "["+ UUID.randomUUID().toString()+"]";
                        clientMap.put(key,client);
                    }else if(selectionKey.isReadable()){
                        client = (SocketChannel)selectionKey.channel();
                        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                        int count = client.read(readBuffer);
                        if(count>0){
                            readBuffer.flip();
                            Charset charset = Charset.forName("utf-8");
                            String receiveMessage = String.valueOf(charset.decode(readBuffer).array());
                            System.out.println(client+":"+receiveMessage);

                            String  senderKey = null;
                            for(Map.Entry<String,SocketChannel> entry:clientMap.entrySet()){
                              if(client == entry.getValue()){
                                  senderKey = entry.getKey();
                                  break;
                              }
                            }
                            for(Map.Entry<String,SocketChannel> entry:clientMap.entrySet()){
                                SocketChannel value = entry.getValue();
                                ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
                                writeBuffer.put((senderKey+":"+receiveMessage).getBytes());
                                writeBuffer.flip();
                                value.write(writeBuffer);
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }


            });
            selectionKeys.clear();
        }

    }
}

在这里插入图片描述
在这里插入图片描述

使用客户端代码

	package com.kkagr.nio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.time.LocalDateTime;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NioClient {
    public static void main(String[] args) {
        try {
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            Selector selector = Selector.open();
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
            socketChannel.connect(new InetSocketAddress("127.0.0.1",8899));
            while(true){
                selector.select();
                Set<SelectionKey> ketSet = selector.selectedKeys();
                for(SelectionKey selectionKey:ketSet){
                    if(selectionKey.isConnectable()){
                        SocketChannel client = (SocketChannel) selectionKey.channel();
                        if(client.isConnectionPending()){
                            client.finishConnect();
                            ByteBuffer writeByffer = ByteBuffer.allocate(1024);
                            writeByffer.put((LocalDateTime.now()+"连接成功").getBytes());
                            writeByffer.flip();
                            client.write(writeByffer);
                            ExecutorService executorService = Executors.newSingleThreadExecutor(Executors.defaultThreadFactory());
                            executorService.submit(()->{
                                while(true){
                                    try {
                                        writeByffer.clear();
                                        InputStreamReader input = new InputStreamReader(System.in);
                                        BufferedReader br = new BufferedReader(input);
                                        String sendMessage = br.readLine();
                                        writeByffer .put(sendMessage.getBytes());
                                        writeByffer.flip();
                                        client.write(writeByffer);
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                }
                            });
    ;                    }
                        client.register(selector,SelectionKey.OP_READ);
                    }else if(selectionKey.isReadable()){
                        SocketChannel client = (SocketChannel) selectionKey.channel();
                        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                        int count = client.read(readBuffer);
                        if(count>0){
                            String readMessage = new String(readBuffer.array(),0,count);
                            System.out.println(readMessage);
                        }
                    }
                }
                ketSet.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值