基于零拷贝技术的的java NIO文件下载服务器_weixin_34378767的博客-程序员秘密

技术标签: java  操作系统  

什么是零拷贝?
我们首先来认识一下传统的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<SelectionKey> 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:\\Users\\dell\\Desktop\\ZOL手机数据(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<SelectionKey> 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:\\Users\\dell\\Desktop\\ZOL手机数据(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。因为在这套体系里,不仅仅提供了非阻塞的编程模型,而且提供了类似零拷贝,内存映射这样的新技术(对于操作系统来说早就有了)。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_34378767/article/details/88535096

智能推荐

PPC版本Dialog的滚动条的实现且焦点切换的时候带动滚动条_weixin_33728268的博客-程序员秘密

上面的代码只解决了用滚动条拖动屏幕,如果要实现焦点切换的时候带动滚动条运动,还需要处理不少代码。在什么位置上处理焦点切换事件? WM_COMMAND消息中处理EN_SETFOCUS,这样可以在一个地方处理焦点切换事件。解决了Edit的焦点切换问题,新问题来了-EN_SETFOCUS是EDIT控件发送的,DTP控件没有这个事件怎么办?子类化后只处理...

CUDA版本与显卡驱动匹配_cuda驱动_Zhninu的博客-程序员秘密

一、已知显卡驱动,安装对应版本的CUDANVIDIA 控制面板帮助&gt;&gt;系统信息组件可以查看对应的CUDA driver版本,下载对应的驱动。这个CUDA driver是在NVIDIA驱动中自带的。二、想要安装固定版本的CUDA,查看驱动是否匹配,或者更新驱动https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html上面网站是官方的CUDA版本和驱动对应的表格。根...

Windows10环境下安装graphviz和pygraphviz(亲测成功)_window 下载 pygraphviz_斯特兰奇的博客-程序员秘密

一、安装graphviz1.安装包方式安装,下载匹配电脑的版本 安装graphviz可视化工具网址:http://www.graphviz.org/download/2.双击下载的msi文件,一路next(记住安装路径,后面配置环境变量会用到路径信息),安装完成之后,会在windows开始菜单创建快捷信息,默认快捷方式不放在桌面3.配置环境变量将graphviz安装目录下的bin文件夹添加到Path环境变量中:或者是,用Anaconda Prompt安装graphviz..

2016年人工智能产业梳理:一朝引爆,稳步前进(中篇)_weixin_34388207的博客-程序员秘密

一场人机大战引起了人工智能热,在其普及的背后,是整个产业的稳健布局。 在基础层、应用层、软件和媒体四个人工智能产业划分中,在技术之外,应用层更多关注的是用户的需求。基于用户的需求,将产品与人工智能技术相糅合,才能让技术和产品得到“落地”,而不是如同“鸡肋”。在应用层方面,人工智能的应用主要分为机器人、无人机、无人...

early printk使用_JerryMo06的博客-程序员秘密

当kernel启动不了,但又没有什么提示消息时,可以打开early printk查看。这是因为在内核刚启动时,有些打印语句可能在串口还没有注册之前就调用了,那当然不能显示啦,early printk就是实现这个功能。选上以下内核配置就可以了:Kernel hacking  ---> Kernel low-level debugging functions -->   Early pri

随便推点

KETTLE ETL数据迁移工具 使用教程_丶的疲倦的博客-程序员秘密

Kettle的建立数据库连接、使用kettle进行简单的全量对比插入更新:kettle会自动对比用户设置的对比字段,若目标表不存在该字段,则新插入该条记录。若存在,则更新。Kettle简介:Kettle是一款国外开源的ETL工具,纯java编写,可以在Window、Linux、Unix上运行,数据抽取高效稳定。Kettle 中文名称叫水壶,该项目的主程序员MATT 希望把各种数据放到一个...

不服不行!java编程思想第六版下载_蛋黄酥呀的博客-程序员秘密

01 源码分析源码阅读,最核心有三点:技术基础+强烈的求知欲+耐心。1.1 设计模式(45设计模式:介绍+优缺点+应用实例+源代码+解决问题)1.2 Spring复习大纲:依赖注入Ioc+Beans+注解+数据访问+AOP+MVC等1.3 Spring全家桶笔记:Spring+Spring Boot+Spring Cloud+Spring MVC面试题(含解析)+学习书籍+学习思维脑图02 分布式架构近几年目前分布式最主流的技术:2.1 大规模分布式存储系统:原理解析与架构实战(

10.傅里叶变换——达利画家、基集(Basis Set)、傅里叶级数(Fourier Series)_1_傅里叶基_Tom Boom的博客-程序员秘密

目录达利-西班牙画家基集(BasisSet)傅里叶级数(Fourier Series)介绍好的,欢迎回到计算机视觉。我们看一下,我们把图像作为函数做了一点,然后开始讨论边缘。然后我们绕了一圈我们讨论了霍夫变换利用这些图像作为证据来提取信息。现在我们回到图像处理上来。现在,我们要讲的是频率分析。在过去,这已经很古老了。现在我们谈论的是40年前,30年,40年前。你们中所有要研究...

Mybatis中使用JDK8的日期API-LocalDateTime_localdatetime的set_狂奔的蜗牛Evan的博客-程序员秘密

序言  本次所学习使用的Mysql版本:5.7.20,Mybatis版本3.4.0,JDBC版本5.1.30。概述  在使用Mybatis这种半自动化的框架中,我们都知道,实体Entity的属性与数据库中表的字段存在着一种映射关系,我们以MySql举例,比如表中varchar与java中String的映射,date与java.sql.Date,time与java.sql.Time,...

LeetCode-461. 汉明距离(python3)_康雨城的博客-程序员秘密

两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。给出两个整数 x 和 y,计算它们之间的汉明距离。

GitHub:用户名或密码无效_hi weilaikeqin! you've successfully authenticated,_CHCH998的博客-程序员秘密

I have a project hosted on GitHub. 我有一个在GitHub上托管的项目。 I fail when trying to push my modifications o

推荐文章

热门文章

相关标签