NIO选择器selector的使用详解---实现文件传输功能

什么是选择器Selector

选择器是NIO技术的核心组件(缓冲区Buffer、通道Channel、选择器Selector)之一。选择器的主要作用是使用1个线程来对多个通道中的已经就绪通道进行选择,选择出就绪的通道后,就可以对通道中的数据进行处理。选择器核心类包括Selector、SelectionKey、SelectableChannel。

通道的标记SelectionKey

每个注册到选择器中的通道,都有一个代表通道的SelectionKey对象。

可选择通道SelectableChannel

  1. ServerSocketChannel
  2. SocketChannel
  3. DatagramChannel
  4. SctpChannel
  5. SctpMultiChannel
  6. SctpServerChannel
  7. SinkChannel
  8. SourceChannel

通道的操作类型

  1. OP_ACCEPT
  2. OP_CONNECT
  3. OP_READ
  4. OP_WRITE

ServerSocketChannel和SocketChannel使用

Server端:

try {
            ServerSocketChannel channel = ServerSocketChannel.open();
            //设置为非阻塞模式
            channel.configureBlocking(false);
            channel.bind(new InetSocketAddress("localhost",8088));
            //打开选择器
            Selector selector = Selector.open();
            //注册连接通道
            channel.register(selector, SelectionKey.OP_ACCEPT);
            while (true){
                //选择已就绪的key
                selector.select();
                //获取已就绪的key的集合
                Set selectionKeys = selector.selectedKeys();
                Iterator iterator = selectionKeys.iterator();

                while (iterator.hasNext()){
                    SelectionKey readyKey = iterator.next();
                    iterator.remove();
                    //判断当前已就绪key是否是连接通道的key
                    if(readyKey.isAcceptable()) {
                        //接收客户端的连接
                        SocketChannel accept = channel.accept();
                        accept.configureBlocking(false);
                        //注册读取客户端数据的通道
                        accept.register(selector, SelectionKey.OP_WRITE);
                    }
                    //判断当前key是否是可写入的通道
                    if(readyKey.isWritable()){
                        SocketChannel socketChannel = (SocketChannel) readyKey.channel();
                        File file = new File("D:\\test001.txt");
                        FileInputStream fileInputStream = new FileInputStream(file);
                        FileChannel fileChannel = fileInputStream.getChannel();
                        // 设置帧头写入缓冲区,回写消息给客户端
                        boolean isFrame=true;
                        while (fileChannel.position()

Client端

try {
            SocketChannel socketChannel_1 = SocketChannel.open();
            socketChannel_1.configureBlocking(false);
            socketChannel_1.connect(new InetSocketAddress("localhost", 8088));
            Selector open = Selector.open();
            socketChannel_1.register(open, SelectionKey.OP_CONNECT);
            while (true) {
                open.select();
                Set selectionKeys = open.selectedKeys();
                Iterator iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey next = iterator.next();
                    iterator.remove();
                    if (next.isConnectable()) {
                        while (!socketChannel_1.finishConnect()) {
                        }
                        socketChannel_1.register(open, SelectionKey.OP_READ);
                    }
                    if (next.isReadable()) {
                        ByteBuffer allocate = ByteBuffer.allocate(1024);
                        int read = socketChannel_1.read(allocate);
                        while (read !=-1) {
                            read = socketChannel_1.read(allocate);
                        }
                        allocate.flip();
                        if(allocate.remaining() > 0 ) {
                            int isFrame = allocate.getInt();
                            //读取frame
                            if (isFrame == 0) {
                                int anInt = allocate.getInt();
                                System.out.println("filename length = " + anInt);
                                byte[] bytes = new byte[anInt];
                                allocate.get(bytes);
                                System.out.println("filename : " + new String(bytes, "utf8"));
                                long length = allocate.getLong();
                                System.out.println("content length = " + length);
                            }
                            //读取数据,写入本地文件
                            File file = new File("E:\\test001.txt");
                            if(!file.exists()){
                                file.createNewFile();
                            }
                            FileOutputStream fileInputStream = new FileOutputStream(file);
                            FileChannel fileChannel = fileInputStream.getChannel();
                            fileChannel.write(allocate);
                        }
                        allocate.clear();
                    }
                }


            }
        } catch (IOException e) {
            e.printStackTrace();
        }

你可能感兴趣的:(java基础)