BIO就是传统的socket编程。每有一个客户端连入,服务端就须要另起线程为其服务,很容易形成资源枯竭。html
Channel管道比做成铁路,buffer缓冲区比做成火车(运载着货物)java
public static void main(String[] args) { // 建立一个缓冲区 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); // 添加一些数据到缓冲区中 String s = "Java3y"; byteBuffer.put(s.getBytes()); //切换成读模式 byteBuffer.flip(); // 建立一个limit()大小的字节数组(由于就只有limit这么多个数据可读) byte[] bytes = new byte[byteBuffer.limit()]; // 将读取的数据装进咱们的字节数组中 byteBuffer.get(bytes); // 输出数据 System.out.println(new String(bytes, 0, bytes.length)); }
// 1. 经过本地IO的方式来获取通道 FileInputStream fileInputStream = new FileInputStream("F:\\3yBlog\\JavaEE经常使用框架\\Elasticsearch就是这么简单.md"); // 获得文件的输入通道 FileChannel inchannel = fileInputStream.getChannel(); // 2. jdk1.7后经过静态方法.open()获取通道 FileChannel.open(Paths.get("F:\\3yBlog\\JavaEE经常使用框架\\Elasticsearch就是这么简单2.md"), StandardOpenOption.WRITE);
复制文件编程
使用内存映射文件的方式实现文件复制的功能(直接操做缓冲区):设计模式
通道之间经过transfer()
实现数据的传输(直接操做缓冲区):数组
阻塞I/O:网络
非阻塞I/O:并发
I/O多路复用:框架
在Linux下对文件的操做是利用文件描述符(file descriptor)来实现的。socket
在Linux下它是这样子实现I/O复用模型的:调用select/poll/epoll/pselect
其中一个函数,传入多个文件描述符,若是有一个文件描述符就绪,则返回,不然阻塞直到超时。函数
因此,I/O 多路复用的特色是经过一种机制一个进程能同时等待多个文件描述符,而这些文件描述符其中的任意一个进入读就绪状态,select()函数就能够返回。select/epoll的优点并非对于单个链接能处理得更快,而是在于能处理更多的链接。
IO多路复用对应的设计模式:Reactor模式
http://www.javashuo.com/article/p-yeqleamk-kt.html
1、普通拷贝
read(file, tmp_buf, len); write(socket, tmp_buf, len);
能够看到,普通的拷贝过程经历了四次内核态和用户态的切换(上下文切换),两次CPU从内存中进行数据的读写过程,这种拷贝过程相对来讲比较消耗系统资源。
2、零拷贝
内存映射方式(NIO中的map()就是用的这种):
tmp_buf = mmap(file, len); write(socket, tmp_buf, len);
能够看到这种内存映射的方式减小了CPU的读写次数,可是用户态到内核态的切换(上下文切换)依旧有四次(调用map()是两次,调用write()是两次),同时须要注意在进行这种内存映射的时候,有可能会出现并发线程操做同一块内存区域而致使的严重的数据不一致问题,因此须要进行合理的并发编程来解决这些问题。
sendfile()方式(NIO中的transfer()就是用的这种):
sendfile(socket, file, len);
依旧有一次CPU进行数据拷贝,两次用户态和内核态的切换操做,相比较于内存映射的方式有了很大的进步,但问题是程序不能对数据进行修改,而只是单纯地进行了一次数据的传输过程。
===========================
NIO:
https://juejin.im/post/5af942c6f265da0b7026050c
ZeroCopy:
https://blog.csdn.net/cringkong/article/details/80274148
https://www.jianshu.com/p/8c6b056f73ce