- 定义 : Java 中把不同的 输入/ 输出源 ,抽象的表示成流(steam
- 好处 : 因为Java 中提供IO流的抽象,所以开发者 可以采用一致的IO代码 读写各种各样的IO流节点
- 分类
-
1、按照流向 可以分为 输入流 、输出流
- 输入流 : 只能从中读取数据,不能往里面写入数据
- 输出流 : 只能从中写入数据,不能往里面读取数据
-
2、按照操作的数据单元不同,可以分为 字节流、字符流
- 字节流 : 操作的数据单元是 8位的字节,以InputSteam和OutputSteam 作为基类
- 字符流 : 操作的数据单元是16位的字符,以Reader 和 Writer 作为基类
-
3、按照流的角色来分 分为 节点流 和 字符流
- 节点流 : 程序直接操作的数据源的流
- 处理流 : 对流进行了包装,程序并没有直接操作数据流
-
使用处理流的好处
Java 中的处理流来包装节点流 是 典型的 装饰器设计模式,通过使用处理流来包装节点流,可以消除不同的节点流之间的差异,也可以更加方便的完成输入输出功能- 性能的提高 : 增加了 缓冲的方式 来提高 输入/输出 的效率
- 操作的便捷 :处理流提供便捷的方式 一次输入/输出大量的数据
-
Java中网络编程的IO模型
BIO模型 (面向流(Stream)
- BIO模型是一种 同步阻塞模型,服务器 实现模式是 一个连接一个线程
每当有一个客户端连接 就需要分配一个线程去处理,对性能开销特别大
- 总结BIO通信流程
- 服务端 启动一个ServerSocket注册端口,调用accept方法,监听客户端的请求
- 客户端启动Socket 绑定Ip地址和端口,对服务器进行通信,默认情况下,一个客户端的通信,需要服务端启动一个线程来对应处理
NIO模型 (面向缓冲区)
NIO模型是一种支持非阻塞式IO通信的模型
三大组成 通道Channel 缓冲区Buffer 选择器Selector
- Channel : 负责通信的连接
- Buffer : 负责传输数据
- Selector : 是一个NIO组件,负责管理Channel
NIO非阻塞式网络通信原理分析
服务端流程
- 1、当客户端连接服务端时,服务端会通过 ServerSocketChannel 得到 SocketChannel:1. 获取通道
ServerSocketChannel ssChannel = ServerSocketChannel.open();
- 2、切换非阻塞模式
ssChannel.configureBlocking(false);
- 3、绑定连接
ssChannel.bind(new InetSocketAddress(9999));
- 4、 获取选择器
Selector selector = Selector.open();
- 5、 将通道注册到选择器上, 并且指定“监听接收事件”
ssChannel.register(selector, SelectionKey.OP_ACCEPT);
-
读 : SelectionKey.OP_READ (1)
-
写 : SelectionKey.OP_WRITE (4)
-
连接 : SelectionKey.OP_CONNECT (8)
-
接收 : SelectionKey.OP_ACCEPT (16)
-
6.轮询式的获取选择器上已经“准备就绪”的事件
//轮询式的获取选择器上已经“准备就绪”的事件,没有事件时候select阻塞
while (selector.select() > 0) {
//7. 获取当前选择器中所有注册的“选择键(已就绪的监听事件)”
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
//8. 获取准备“就绪”的是事件
SelectionKey sk = it.next();
//9. 判断具体是什么事件准备就绪
if (sk.isAcceptable()) {//如果是连接事件
//10. 若“接收就绪”,获取客户端连接
SocketChannel sChannel = ssChannel.accept();
//11. 切换非阻塞模式
sChannel.configureBlocking(false);
//12. 将该通道注册到选择器上
sChannel.register(selector, SelectionKey.OP_READ);
} else if (sk.isReadable()) {
//13. 获取当前选择器上“读就绪”状态的通道
SocketChannel sChannel = (SocketChannel) sk.channel();
//14. 读取数据
ByteBuffer buf = ByteBuffer.allocate(1024);
int len = 0;
while ((len = sChannel.read(buf)) > 0) {
buf.flip();
System.out.println(new String(buf.array(), 0, len));
buf.clear();
}
}
//15. 取消选择键 SelectionKey
it.remove();
}
}
}
客户端流程
- 1.获取通道
SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9999));
- 2.切换非阻塞模式
sChannel.configureBlocking(false);
3.分配指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
- 4.发送数据给服务端
Scanner scan = new Scanner(System.in);
while(scan.hasNext()){
String str = scan.nextLine();
buf.put((new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(System.currentTimeMillis())
+ "\n" + str).getBytes());
buf.flip();
sChannel.write(buf);
buf.clear();
}
//关闭通道
sChannel.close();
AIO模型
AIO是一种异步非阻塞的模型
异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理
可以理解为,read/write方法都是异步的,完成后会主动调用回调函数
三种模型的适用场景分析
- BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中
- NIO方式适用于**连接数目多且连接比较短(轻操作)**的架构,比如聊天服务器,并发局限于应用中,编程比较复杂
- AIO方式使用于**连接数目多且连接比较长(重操作)**的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂