• 【对线面试官】Java NIO


    服务端:

    public class NoBlockServer {
    
        public static void main(String[] args) throws IOException {
    
            // 1.获取通道
            ServerSocketChannel server = ServerSocketChannel.open();
    
            // 2.切换成非阻塞模式
            server.configureBlocking(false);
    
            // 3. 绑定连接
            server.bind(new InetSocketAddress(6666));
    
            // 4. 获取选择器
            Selector selector = Selector.open();
    
            // 4.1将通道注册到选择器上,指定接收“监听通道”事件
            server.register(selector, SelectionKey.OP_ACCEPT);
    
            // 5. 轮训地获取选择器上已“就绪”的事件--->只要select()>0,说明已就绪
            while (selector.select() > 0) {
                // 6. 获取当前选择器所有注册的“选择键”(已就绪的监听事件)
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
    
                // 7. 获取已“就绪”的事件,(不同的事件做不同的事)
                while (iterator.hasNext()) {
    
                    SelectionKey selectionKey = iterator.next();
    
                    // 接收事件就绪
                    if (selectionKey.isAcceptable()) {
    
                        // 8. 获取客户端的链接
                        SocketChannel client = server.accept();
    
                        // 8.1 切换成非阻塞状态
                        client.configureBlocking(false);
    
                        // 8.2 注册到选择器上-->拿到客户端的连接为了读取通道的数据(监听读就绪事件)
                        client.register(selector, SelectionKey.OP_READ);
    
                    } else if (selectionKey.isReadable()) { // 读事件就绪
    
                        // 9. 获取当前选择器读就绪状态的通道
                        SocketChannel client = (SocketChannel) selectionKey.channel();
    
                        // 9.1读取数据
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
    
                        // 9.2得到文件通道,将客户端传递过来的图片写到本地项目下(写模式、没有则创建)
                        FileChannel outChannel = FileChannel.open(Paths.get("2.png"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
    
                        while (client.read(buffer) > 0) {
                            // 在读之前都要切换成读模式
                            buffer.flip();
    
                            outChannel.write(buffer);
    
                            // 读完切换成写模式,能让管道继续读取文件的数据
                            buffer.clear();
                        }
                    }
                    // 10. 取消选择键(已经处理过的事件,就应该取消掉了)
                    iterator.remove();
                }
            }
    
        }
    }
    

    客户端:

    public class NoBlockClient {
    
        public static void main(String[] args) throws IOException {
    
            // 1. 获取通道
            SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 6666));
    
            // 1.1切换成非阻塞模式
            socketChannel.configureBlocking(false);
    
            // 1.2获取选择器
            Selector selector = Selector.open();
    
            // 1.3将通道注册到选择器中,获取服务端返回的数据
            socketChannel.register(selector, SelectionKey.OP_READ);
    
            // 2. 发送一张图片给服务端吧
            FileChannel fileChannel = FileChannel.open(Paths.get("X:\Users\ozc\Desktop\面试造火箭\1.png"), StandardOpenOption.READ);
    
            // 3.要使用NIO,有了Channel,就必然要有Buffer,Buffer是与数据打交道的呢
            ByteBuffer buffer = ByteBuffer.allocate(1024);
    
            // 4.读取本地文件(图片),发送到服务器
            while (fileChannel.read(buffer) != -1) {
    
                // 在读之前都要切换成读模式
                buffer.flip();
    
                socketChannel.write(buffer);
    
                // 读完切换成写模式,能让管道继续读取文件的数据
                buffer.clear();
            }
    
    
            // 5. 轮训地获取选择器上已“就绪”的事件--->只要select()>0,说明已就绪
            while (selector.select() > 0) {
                // 6. 获取当前选择器所有注册的“选择键”(已就绪的监听事件)
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
    
                // 7. 获取已“就绪”的事件,(不同的事件做不同的事)
                while (iterator.hasNext()) {
    
                    SelectionKey selectionKey = iterator.next();
    
                    // 8. 读事件就绪
                    if (selectionKey.isReadable()) {
    
                        // 8.1得到对应的通道
                        SocketChannel channel = (SocketChannel) selectionKey.channel();
    
                        ByteBuffer responseBuffer = ByteBuffer.allocate(1024);
    
                        // 9. 知道服务端要返回响应的数据给客户端,客户端在这里接收
                        int readBytes = channel.read(responseBuffer);
    
                        if (readBytes > 0) {
                            // 切换读模式
                            responseBuffer.flip();
                            System.out.println(new String(responseBuffer.array(), 0, readBytes));
                        }
                    }
    
                    // 10. 取消选择键(已经处理过的事件,就应该取消掉了)
                    iterator.remove();
                }
            }
        }
    
    }
    

    文章以纯面试的角度去讲解,所以有很多的细节是未铺垫的。

    鉴于很多同学反馈没看懂【对线面试官】系列,基础相关的知识我确实写过文章讲解过啦,但有的同学就是不爱去翻。

    为了让大家有更好的体验,我把基础文章也找出来(重要的知识点我还整理过电子书,比如说像多线程、集合这种面试必考的早就已经转成PDF格式啦)

    我把这些上传到网盘,你们有需要直接下载就好了。做到这份上了,不会还想白嫖吧点赞转发又不用钱。

    链接:https://pan.baidu.com/s/1pQTuKBYsHLsUR5ORRAnwFg 密码:3wom

    欢迎关注我的微信公众号【Java3y】来聊聊Java面试

  • 相关阅读:
    zoj 3233 容斥原理 + 双条件
    bzoj 1038 瞭望塔 半平面交 + 最小值 枚举
    linux 常用命令
    Vue路由
    luffycity项目开发
    Vue组件化开发
    Vue对象提供的属性功能
    Vue快速入门
    Django-DRF(路由与扩展功能)
    Django-DRF(视图相关)
  • 原文地址:https://www.cnblogs.com/Java3y/p/14263729.html
Copyright © 2020-2023  润新知