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);
}
}
}
以上代码只是案例的一部分仅供参考!!!