一、I/O基础
输入流:InputStream和Reader 输出流:OutputStream和Writer
字节流 字符流
计算机最小的二进制单位 bit 比特 代表0和1 字节 1 byte = 8bit 计算机处理的最小单位 字符 1 char = 2byte = 16bit 人处理的最小单位
所以,字节流处理文件、图片、视频等二进制数据,而字符流处理文本数据。
下面写一个示例
import java.io.*;
public class BioTest {
public static void main(String[] args) throws IOException {
copy("io.txt","io1.txt");
}
//读取数据
public static void read() throws IOException {
File file = new File("io.txt");
if(!file.exists()){
file.createNewFile();
}
//读取字节数据
FileInputStream inputStream = new FileInputStream(file);
FileReader fileReader = new FileReader(file);//使用字符流
char[] chars = new char[(int)file.length()];//使用一个char数组类承接内容
int read1 = fileReader.read(chars);
System.out.println("读取字节的大小"+read1+"读取的内容"+new String(chars));
byte[] byteArr = new byte[(int)file.length()];//使用一个byte数组来承接内容
int read = inputStream.read(byteArr);
System.out.println("读取字节的大小"+read+"读取的内容"+new String(byteArr));
fileReader.close();
inputStream.close();
}
//写入数据
public static void write() throws IOException {
File file = new File("io.txt");
if(!file.exists()){
file.createNewFile();
}
//写入字节数据
String str = "--hello bio";
FileOutputStream fileOutputStream = new FileOutputStream(file,true);
fileOutputStream.write(str.getBytes());
fileOutputStream.flush();;
fileOutputStream.close();
}
public static void copy(String src,String dest) throws IOException {
File srcFile = new File(src);
File destFile = new File(dest);
if(!destFile.exists()){
destFile.createNewFile();
}
FileInputStream inputStream = new FileInputStream(srcFile);
FileOutputStream fileOutputStream = new FileOutputStream(destFile);
byte[] bytes = new byte[1024];
int read = 0;
//当读取到文件尾退出循环
while((read = inputStream.read(bytes)) != -1){
fileOutputStream.write(bytes,0,read);
}
fileOutputStream.flush();
inputStream.close();
fileOutputStream.close();
}
public static void copy1(String src,String dest) throws IOException {
File srcFile = new File(src);
File destFile = new File(dest);
if(!destFile.exists()){
destFile.createNewFile();
}
FileInputStream inputStream = new FileInputStream(srcFile);
BufferedInputStream bis = new BufferedInputStream(inputStream);
FileOutputStream fileOutputStream = new FileOutputStream(destFile);
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
int read = 0;
//当读取到文件尾退出循环
while((read = bis.read()) != -1){
bos.write(read);
}
fileOutputStream.flush();
inputStream.close();
fileOutputStream.close();
}
}
二、Socket
原意是“插座”,在计算机领域中,翻译为“套接字”。 本质上,是计算机之间进行通信的一种方式。
Linux,“一切皆文件”,给每个文件映射一个ID,叫做"文件描述符"。 当处理网络连接时,也会看成一个文件,read/write变成和远程计算机的交互。
OSI七层模型 = Open System Interconnection 开放式系统互联 从下到上分别为:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
实际应用的是优化后的TCP/IP模型(四层) 网络接口层/链路层、网络层、传输层、应用层
应用层协议:HTTP、FTP、SMTP(邮件协议) 传输层协议:TCP、UDP
Socket其实是应用层与传输层之间的抽象层,是一组接口。 在设计模式中,是门面模式。
3、NIO
BIO - BlockingIO 同步阻塞 NIO - New IO / Non-Blocking IO 同步非阻塞 AIO - Asynchronous IO 异步非阻塞
同步和异步,关注的是消息通知的机制 阻塞和非阻塞,关注的是等待消息过程中的状态
多路复用的模型
三大元素:Channel 、Buffer、Selector
1) Channel
FileChannel 文件管道的数据 Pipe.SinkChannel Pipe.SourceChannel 线程间通信的管道 ServerSocketChannel SocketChannel 用于TCP网络通信的管道 DatagramChannel 用于UDP网络通信的管道
2) Buffer
capacity 总体容量大小
limit 存储容量的大小,是可读写和不可读写的界线
position 已读容量的大小,已读和未读区域的界线
【使用原理】
a) 初始化,给定总容量,position=0, limit=capacity
b) 当使用put方法存入数据是,通过position来记录存储的容量变化,position不断后移,直到存储结束(写完成)
c)写完成需要调用flip方法刷新,limit=position,position=0 保障limit记录的是可读写区域的大小,position已读部分重置为空
d) 读数据直到读完成,需要调用clear方法,position=0, limit=capacity
3) Selector
三个元素: Selector选择器、SelectableChannel可选择的通道、SelectionKey选择键
本质上,Selector是监听器,监听的是通道是否有我们关心的操作产生,操作对应的是事件(连接、接收、读/写),使用SelectionKey代表具体的事件,在确保通道是可选择的情况下,将通道注册进选择器中,此时Selector维护的是,通道和事件之间的关联关系。
Selector,管理被注册的通道集合,以及他们的状态
SelectableChannel,是一个抽象类,提供了通道可被选择需要实现的api。
FileChannel就不是可选择的,Socket相关的通道都是可选择的
一个通道可以被注册到多个选择器上吗? 可以的
多个通道可以注册到一个选择器上,但一个通道只能在一个选择器中注册一次
SelectionKey,封装了要监听的事件,连接、接收、读、写。 一方面,Selector关心通道要处理哪些事件 另一方面,当事件触发时,通道要处理哪些事件
【使用方式】
a、首先通过open方法,获取通道,将通道设置为非阻塞的
b、通过open方法,获取选择器,将通道注册进选择器中,伴随设置通道要处理的事件(OP_ACCEPT)
c、轮询选择器,当前是否有要处理的操作 select() > 0? 如果有,要获取待处理操作的集合Set<SelectionKey> , 进行遍历 遍历到SelectionKey时,判断对应哪种操作,不同的操作设置不同的处理方式 如OP_ACCEPT,接收客户端通道并进行注册,监听后续处理的事件,如OP_WRITE 如OP_WRITE,通过key的方法获取通道本身,读取数据并继续监听事件,如OP_READ
4、零拷贝
需求:将磁盘中的文件读取出来,通过socket发送出去
传统的拷贝方式(4次)
Socket网络缓冲区,也属于操作系统的内核缓冲区。
在操作系统中进行的拷贝(如第二次和第三次),叫做CPU拷贝。
连接磁盘或网卡等硬件的拷贝(如第一次和第四次),叫做DMA拷贝。
零拷贝的概念:减少CPU拷贝的次数。
零拷贝是基于操作系统层面的优化方式(以下基于Linux系统)
1) mmap = memory mapping 内存映射
2)sendfile (linux2.1内核支持)
3) sendfile with scatter/gather copy(批量sendfile)
从单个文件的处理,上升到多个物理地址的处理,提高处理速度
4)splice (拼接,在linux2.6内核支持)
在操作系统内核缓冲区和Socket网络缓冲区之间建立管道,来减少拷贝次数。