服务端BIO转化成IO多路复用(多线程转单线程)

1.什么是BIO?什么是IO多路复用?

BIO(Blocking I/O)是传统的同步阻塞式I/O模型,在这种模型中,一个线程只能处理一个连接,当一个连接有数据到达时,线程会被阻塞,直到数据读完或者连接关闭,才能继续处理其他连接,性能太低,高并发情况下线程会不够用

IO多路复用(也叫NIO)(I/O Multiplexing)是一种异步非阻塞式I/O模型,它允许一个线程同时处理多个连接,当某个连接有数据到达时,线程会收到通知,然后可以选择处理这个连接,也可以继续处理其他连接。

2.IO多路复用对比BIO有什么优点?

(1)提高线程的并发性。在BIO模型中,每个连接都需要一个线程来处理,当连接数很多时,会消耗大量的线程资源,IO多路复用模型只需要一个线程就可以处理多个连接

(2)减少线程切换的开销。在BIO模型中,当一个连接有数据到达时,线程会被阻塞,直到数据读完或者连接关闭,才能继续处理其他连接。而IO多路复用模型中,当某个连接有数据到达时,线程会收到通知,然后可以选择处理这个连接,也可以继续处理其他连接

(3)提高了响应的速度。在BIO模型中,当一个连接有数据到达时,线程会被阻塞,直到数据读完或者连接关闭,才能继续处理其他连接。而IO多路复用模型中,当某个连接有数据到达时,线程会收到通知,然后可以立即处理这个连接,这样就提高了响应速度

3.什么时候用到IO多路复用?

(1)当需要处理大量的连接时。

(2)当需要减少线程切换的开销时。 

(3)当需要提高响应速度时。

4.IO多路复用三要素

(1)通信管道

(2)缓冲区

(3)选择器

5.服务端IO多路复用的使用步骤

因为BIO的线程会被阻塞,所以主要问题就是不阻塞

(1)建立(ServerSocketChanel)通信管道

//建立通信管道,并且设置为开放状态
ServerSocketChannel ssc = ServerSocketChannel.open();

(2)绑定IP端口

 //2.绑定id端口
ssc.bind(new InetSocketAddress(8089));

(3)设置通信管道为非阻塞状态

ssc.configureBlocking(false);

(4)建立一个选择器

Selector selector = Selector.open();

(5)将通信管道注册给选择器(管理者)来管理

//在BIO的时候主要是accept接受客户端在等导致阻塞
//所以我们要将阻塞交给选择器来处理,选择的类型是OP_ACCEPT
ssc.register(selector, SelectionKey.OP_ACCEPT);

(6)客户端连接,进入事件循环,不断调用Selector的select()方法等待事件发生。

        在处理可读事件时,通过SocketChannel的read()方法读取客户端发送的数据。

        //说明客户端连接了
        while (true){
                //管理则需要查看是否有事件发生了--HR等待其他同时提交材料
                int select = selector.select();//阻塞
                System.out.println("发生的事件个数是"+select);
                //获取所有事件的key类型
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                //创建一个迭代器
                Iterator<SelectionKey> it = selectionKeys.iterator();
                //判断有没有下一条记录
                while (it.hasNext()){
                    SelectionKey key = it.next();
                    //将对应事件移除掉
                    it.remove();
                    //看key是否为可接受的
                    if (key.isAcceptable()){
                        //说明客户端连接了
                        SocketChannel socketChannel = ssc.accept();
                        //将客户端设置成非阻塞状态
                        socketChannel.configureBlocking(false);
                        //将客户端的读消息事件注册给管理者来管
                        socketChannel.register(selector,SelectionKey.OP_READ);
                        System.out.println("有人连接了" + selectionKeys);
                    } else if (key.isReadable()) {//可读事件
                        //说明客户端发消息过来了,我们需要接受一下
                        System.out.println("有人发消息");
                        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        int read = socketChannel.read(byteBuffer);
                        byte[] array = byteBuffer.array();
                        String s = new String(array, 0, read);
                        System.out.println("读到的是" + s);
                    }
                }
            }

以上代码只是案例的一部分仅供参考!!!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值