1:IO 流
- Byte(字节)是计算机操作数据的最小单位由 8 位 bit 组成 取值(-128-127)
- Char(字符)是用户的可读写的最小单位,在 Java 里面由 16 位 bit 组成 取值(0-65535)
1-1:为何还要有字符流
在各种编码中,一个英文字符就是一个字节。如果只有英文就不会有问题,但是中文一般会占据多个字节。比如 Java 标准采用的 Unicode 编码中就占用两个字节,UTF-8 中占用三个字节,如果不知道字符编码,一次读取一个字节,可能就会将一个字符的多个字节分割开,导致乱码。
字符流是由 Java 虚拟机将字节转换得到的,问题就出在这个过程还算是非常耗时,并且,如果我们不知道编码类型就很容易出现乱码问题。所以, I/O 流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。
1-2:字节流和字符流区别
- 字节流操作的基本单位为字节,字符流操作的基本单元为 Unicode 单元。
- 字节流默认不使用缓冲区,字符流使用缓冲区
- 字节流通常用处理二进制数据,实际上它可以处理任意类型的数据,但它不支持直接写入或读取 Unicode 马原;字符流通常用于处理文本数据,它支持写入和读取 Unicode 码元。
2:BIO\NIO\AIO
2-1:BIO\NIO\AIO 定义
- BIO:同步并阻塞 IO,数据的读取写入必须阻塞在一个线程内等待其完成.使用多线程解决多个客户端访问请求.
- NIO:NIO 与原来的 I/O 有同样的作用和目的, 而 NIO 是支持同步非阻塞的.
- AIO:异步非阻塞 IO
2-2:BIO 与 NIO 的区别
- BIO 是同步非阻塞的,而 NIO 支持同步阻塞和同步非阻塞两种模式
- BIO 面向流,而 NIO 面向缓冲区(Buffer oriented).BIO 中是将数据直接写入或者读取到 Stream 对象中,而 NIO 所有数据都是通过缓冲区处理.在读取数据时,直接冲缓冲区读取,写入数据时,写入到缓冲区.
- NIO 通过 Channel(通道)进行读写,通道是双向的,可以读也可以写,而流的读写是单向的.无论读写,通道只能和 Buffer 交互。也因为 Buffer,通道可以异步地读写。
- NIO 有选择器,BIO 没有.
3:IO 模型
3-1:IO 多路复用
在 IO 多路复用模型中,会有一个线程不断去轮询多个 socket 的状态,只有 socket 真正有读写事件时,才真正调用实际的 IO 读写操作.
因为使用一个线程来管理,不需要创建新的进程或者线程,并且在真正有 IO 事件时才会占用资源,所以大大减少了资源占用.
3-2:IO 多路复用实现方式
- select
- poll
- epoll
3-2-1:三种实现方式区别
select | poll | epoll | |
---|---|---|---|
数据结构 | bitmap | 数组 | 红黑树 |
最大连接数 | 1024 | 无上限 | 无上限 |
fd 拷贝 | 每次调用 select 拷贝 | 每次调用 poll 拷贝 | fd 首次调用 epoll_ct 拷贝,每次调用 epoll_wait 不拷贝 |
工作效率 | 轮询:O(n) | 轮询:O(n) | 回调:O(1) |
3-2-2:三种常用的实现方式优缺点
- select
- 单个进程所打开的 FD 是有限制的,通过 FD_SETSIZE 设置,默认 102
- 每次调用 select,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大
- 对 socket 扫描时是线性扫描,采用轮询的方法,效率较低(高并发时)
- poll
- 每次调用 poll,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大
- 对 socket 扫描时是线性扫描,采用轮询的方法,效率较低(高并发时)
- epoll
- epoll 只能工作在 linux 下