资讯专栏INFORMATION COLUMN

基于零拷贝技术的的java NIO文件下载服务器

Keven / 2923人阅读

摘要:什么是零拷贝我们首先来认识一下传统的操作。因为在这套体系里,不仅仅提供了非阻塞的编程模型,而且提供了类似零拷贝,内存映射这样的新技术对于操作系统来说早就有了。

什么是零拷贝?
我们首先来认识一下传统的I/O操作
假如说用户进程现在要把一个文件复制到另一个地方。
那么用户程序必须先把这个文件读入内存,然后再把内存里的数据写入另一个文件。
不过文件读入内存也不是直接读入用户进程的内存,而是先读入操作系统内核的内存,然后再从操作系统内核的内存区读到用户进程的内存。
与之对应的是,写文件也不是直接写到磁盘上的文件,而是用户进程先把自己内存的数据传到操作系统内核的内存,然后再从操作系统内核的内存区写到磁盘。而这其中涉及到诸多的系统调用
因此看上去简单的操作至少要分为四部
1磁盘文件读入操作系统
2操作系统读到用户进程
3用户进程写到操作系统
4操作系统写入磁盘文件

零拷贝和传统I/O有和不同?
零拷贝就是指,传输一个文件的时候,不需要把文件读到用户进程再处理,而是直接把文件读到操作系统一个内存区,然后再移动到操作系统的另一个内存区,最后写入文件。
这样一来,步骤变成这样:
1磁盘文件读入操作系统
2操作系统把数据写入操作系统另一个区域
3操作系统写入磁盘文件
虽然只少了一步,但是这里不仅减少了数据移动的时间损耗,而且减少了系统调用的次数,因此大大缩短了时间。
更加详细的解释请看https://blog.csdn.net/u010530...

java里如何实现零拷贝呢?
这就要说起java nio中的FileChannel.transferTo()方法了,该方法是把FileChannel中的数据利用零靠的技术转移到另一个channel。这另一个channel往往是FileChannel,不过SocketChannel也是可以的:)。
简单实现(静态下载文件,不能根据用户指令来更改下载的文件。)
代码如下:
单线程版本:

package qiuqi.filedownloadtest;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.*;
import java.util.Iterator;

public class FileServer {

    
    public static void main(String[] args) throws IOException {


        startServer();
    }

    public static void startServer() throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(9999));
        serverSocketChannel.configureBlocking(false);
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (selector.select() > 0)
        {
            Iterator iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext())
            {
                SelectionKey key = iterator.next();
                iterator.remove();
                if(key.isAcceptable())
                {
                 SocketChannel socketChannel = serverSocketChannel.accept();
                 try (FileInputStream in = new FileInputStream("C:UsersdellDesktopOL手机数据(1).rar")){

                         long size = in.available();
                         long num = 0;
                         long begin = 0;
                         while ( (num = in.getChannel().transferTo(begin,size,socketChannel))!=0)
                         {
                             size-=num;
                             begin += num;
                         }
                     socketChannel.close();

                 }
                 catch (IOException e){e.printStackTrace();}

                }
            }
        }


    }
}


多线程版本:

package qiuqi.filedownloadtest;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FileServer {

    static ExecutorService threadpool = Executors.newCachedThreadPool();
    public static void main(String[] args) throws IOException {

        startServer();
    }

    public static void startServer() throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(9999));
        serverSocketChannel.configureBlocking(false);
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (selector.select() > 0)
        {
            Iterator iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext())
            {
                SelectionKey key = iterator.next();
                iterator.remove();
                if(key.isAcceptable())
                {
                 SocketChannel socketChannel = serverSocketChannel.accept();
                    threadpool.execute(new Runnable() {
                        @Override
                        public void run() {
                            try (FileInputStream in = new FileInputStream("C:UsersdellDesktopOL手机数据(1).rar")){

                         long size = in.available();
                         long num = 0;
                         long begin = 0;
                         while ( (num = in.getChannel().transferTo(begin,size,socketChannel))!=0)
                         {
                             size-=num;
                             begin += num;
                         }
                                socketChannel.close();
                            }
                            catch (IOException e){e.printStackTrace();}
                        }
                    });
                 

                }
            }
        }


    }
}

代码就不讲解了。如果学过java nio,那么理解上面的程序轻而易举。
如果不熟悉java nio的服务器编程那么请先学习再来观看。

最后我想说,java NIO真的是NEW IO即新的IO,而不是NonBlocking IO即非阻塞IO。因为在这套体系里,不仅仅提供了非阻塞的编程模型,而且提供了类似零拷贝,内存映射这样的新技术(对于操作系统来说早就有了)。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73543.html

相关文章

  • 彻底理解Netty,这一篇文章就够了

    摘要:如果什么事都没得做,它也不会死循环,它会将线程休眠起来,直到下一个事件来了再继续干活,这样的一个线程称之为线程。而请求处理逻辑既可以使用单独的线程池进行处理,也可以跟放在读写线程一块处理。 Netty到底是什么 从HTTP说起 有了Netty,你可以实现自己的HTTP服务器,FTP服务器,UDP服务器,RPC服务器,WebSocket服务器,Redis的Proxy服务器,MySQL的P...

    yy13818512006 评论0 收藏0
  • MappedByteBuffer VS FileChannel 孰强孰弱?

    摘要:而每个文件系统又可以设置不同的调度算法,另外,还有虚拟内存缺页中断带来的性能毛刺良心的提供了调优的脚本,这点做的不错跑题了。测试环境核线程内存磁盘读写左右虚拟内存未关闭,大小测试注意点为了防止缓存的影响,每次都生成一个新的文件进行读取。 前言 Java 在 JDK 1.4 引入了 ByteBuffer 等 NIO 相关的类,使得 Java 程序员可以抛弃基于 Stream ,从而使用基...

    diabloneo 评论0 收藏0
  • Netty源码解析

    摘要:一旦某个事件触发,相应的则会被调用,并进行处理。事实上,内部的连接处理协议编解码超时等机制,都是通过完成的。开启源码之门理解了的事件驱动机制,我们现在可以来研究的各个模块了。 Netty是什么 大概用Netty的,无论新手还是老手,都知道它是一个网络通讯框架。所谓框架,基本上都是一个作用:基于底层API,提供更便捷的编程模型。那么通讯框架到底做了什么事情呢?回答这个问题并不太容易,我们...

    _Suqin 评论0 收藏0
  • Netty3文档翻译(二)

    摘要:丰富的缓存数据结构使用它自己的缓存来表示字节序列而不是的。针对有一个定义良好的事件模型。有一些协议是多层的建立在其他低级协议基础上。此外,甚至不是完全线程安全的。协议由标准化为。协议缓存整合是一个高效二进制协议的快速实现。 Chapter 2、结构概览 这一节我们将确认Netty提供的核心功能是什么,以及它们怎么构成一个完整的网络应用开发堆栈。 1、丰富的缓存数据结构 Netty使用它...

    Zhuxy 评论0 收藏0
  • 关于拷贝的一点认识

    摘要:前言从字面意思理解就是数据不需要来回的拷贝,大大提升了系统的性能这个词我们也经常在,,,等框架中听到,经常作为其提升性能的一大亮点下面从的几个概念开始,进而在分析零拷贝。 前言 从字面意思理解就是数据不需要来回的拷贝,大大提升了系统的性能;这个词我们也经常在java nio,netty,kafka,RocketMQ等框架中听到,经常作为其提升性能的一大亮点;下面从I/O的几个概念开始,...

    荆兆峰 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<