传统方式read/write send/recv

在传统的文件传输里面(read/write方式),在实现上事实上是比較复杂的,须要经过多次上下文的切换。我们看一下例如以下两行代码:

1. read(file, tmp_buf, len);

2. write(socket, tmp_buf, len);

以上两行代码是传统的read/write方式进行文件到socket的传输。

当须要对一个文件进行传输的时候,其详细流程细节例如以下:

1、调用read函数,文件数据被copy到内核缓冲区

2、read函数返回。文件数据从内核缓冲区copy到用户缓冲区

3、write函数调用。将文件数据从用户缓冲区copy到内核与socket相关的缓冲区。

4、数据从socket缓冲区copy到相关协议引擎。

以上细节是传统read/write方式进行网络文件传输的方式,我们能够看到,在这个过程其中。文件数据实际上是经过了四次copy操作:

硬盘—>内核buf—>用户buf—>socket相关缓冲区(内核)—>协议引擎

新方式sendfile

而sendfile系统调用则提供了一种降低以上多次copy。提升文件传输性能的方法。

Sendfile系统调用是在2.1版本号内核时引进的:

1. sendfile(socket, file, len);

执行流程例如以下:

1、sendfile系统调用,文件数据被copy至内核缓冲区

2、再从内核缓冲区copy至内核中socket相关的缓冲区

3、最后再socket相关的缓冲区copy到协议引擎

相较传统read/write方式,2.1版本号内核引进的sendfile已经降低了内核缓冲区到user缓冲区。再由user缓冲区到socket相关 缓冲区的文件copy,而在内核版本号2.4之后,文件描写叙述符结果被改变,sendfile实现了更简单的方式,系统调用方式仍然一样,细节与2.1版本号的 不同之处在于,当文件数据被拷贝到内核缓冲区时,不再将全部数据copy到socket相关的缓冲区,而是只将记录数据位置和长度相关的数据保存到 socket相关的缓存,而实际数据将由DMA模块直接发送到协议引擎,再次降低了一次copy操作。

一、典型IO调用的问题
一个典型的web服务器传送静态文件(如CSS,JS,图片等)的过程如下:

read(file, tmp_buf, len);
write(socket, tmp_buf, len);

首先调用read将文件从磁盘读取到tmp_buf,然后调用write将tmp_buf写入到socket,在这过程中会出现四次数据copy,过程如图1所示

                图1

1。当调用read系统调用时,通过DMA(Direct Memory Access)将数据copy到内核模式
2。然后由CPU控制将内核模式数据copy到用户模式下的 buffer中
3。read调用完成后,write调用首先将用户模式下 buffer中的数据copy到内核模式下的socket buffer中
4。最后通过DMA copy将内核模式下的socket buffer中的数据copy到网卡设备中传送。

从上面的过程可以看出,数据白白从内核模式到用户模式走了一 圈,浪费了两次copy,而这两次copy都是CPU copy,即占用CPU资源。

二、Zero-Copy&Sendfile()
Linux 2.1版本内核引入了sendfile函数,用于将文件通过socket传送。
sendfile(socket, file, len);
该函数通过一次系统调用完成了文件的传送,减少了原来 read/write方式的模式切换。此外更是减少了数据的copy,sendfile的详细过程图2所示:

                图2

通过sendfile传送文件只需要一次系统调用,当调用 sendfile时:
1。首先通过DMA copy将数据从磁盘读取到kernel buffer中
2。然后通过CPU copy将数据从kernel buffer copy到sokcet buffer中
3。最终通过DMA copy将socket buffer中数据copy到网卡buffer中发送
sendfile与read/write方式相比,少了 一次模式切换一次CPU copy。但是从上述过程中也可以发现从kernel buffer中将数据copy到socket buffer是没必要的。

为此,Linux2.4内核对sendfile做了改进,如图3所示

                图3

改进后的处理过程如下:
1。DMA copy将磁盘数据copy到kernel buffer中
2。向socket buffer中追加当前要发送的数据在kernel buffer中的位置和偏移量
3。DMA gather copy根据socket buffer中的位置和偏移量直接将kernel buffer中的数据copy到网卡上。
经过上述过程,数据只经过了2次copy就从磁盘传送出去了。
(可能有人要纠结“不是说Zero-Copy么?怎么还有两次copy啊”,事实上这个Zero copy是针对内核来讲的,数据在内核模式下是Zero-copy的。话说回来,文件本身在瓷盘上要真是完全Zero-copy就能传送,那才见鬼了 呢)。
当前许多高性能http server都引入了sendfile机制,如nginx,lighttpd等。

三、Java NIO中的transferTo()
Java NIO中
FileChannel.transferTo(long position, long count, WriteableByteChannel target)
方法将当前通道中的数据传送到目标通道target中,在支持Zero-Copy的linux系统中,transferTo()的实现依赖于sendfile()调用。

四、参考文档
《Zero Copy I: User-Mode Perspective》http://www.linuxjournal.com/article/6345?page=0,0
《Efficient data transfer through zero copy》http://www.ibm.com/developerworks/linux/library/j-zerocopy
《The C10K problem》http://www.kegel.com/c10k.html

零拷贝sendfile解析的更多相关文章

  1. Linux "零拷贝" sendfile函数中文说明及实际操作

    Sendfile函数说明 #include ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count); sendfile ...

  2. Linux "零拷贝" sendfile函数中文说明及实际操作分析

    Sendfile函数说明 #include ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count); sendfile ...

  3. linux独有的sendfile系统调用--“零拷贝,高效”

    参考:http://blog.csdn.net/caianye/article/details/7576198 如今几乎每个人都听说过Linux中所谓的"零拷贝"特性,然而我经常碰 ...

  4. java的零拷贝机制

    转:https://blog.csdn.net/zhouhao88410234/article/details/77574689?fps=1&locationNum=9 为何要懂零拷贝原理?因 ...

  5. Linux中“零拷贝”

    服务器响应一个http请求的步骤 把磁盘文件读入内核缓冲区 从内核缓冲区读到内存 处理(静态资源不需处理) 发送到网卡的内核缓冲区(发送缓存) 网卡发送数据 数据从第一步中的内核缓冲区到第四步的内核缓 ...

  6. Linux下的零拷贝

    Reference:  https://segmentfault.com/a/1190000011989008 零拷贝是什么? 维基百科对“零拷贝”是这样描述的: "Zero-copy&qu ...

  7. 框架篇:Linux零拷贝机制和FileChannel

    前言 大白话解释,零拷贝就是没有把数据从一个存储区域拷贝到另一个存储区域.但是没有数据的复制,怎么可能实现数据的传输呢?其实我们在java NIO.netty.kafka遇到的零拷贝,并不是不复制数据 ...

  8. 【Java】Java中的零拷贝

    物理内存 计算机物理内存条的容量,比如我们买电脑会关注内存大小有多少G,这个容量就是计算机的物理内存. 虚拟内存 操作系统为每个进程分配了独立的虚拟地址空间,也就是虚拟内存,虚拟地址空间又分为用户空间 ...

  9. Netty源码解析 -- 零拷贝机制与ByteBuf

    本文来分享Netty中的零拷贝机制以及内存缓冲区ByteBuf的实现. 源码分析基于Netty 4.1.52 Netty中的零拷贝 Netty中零拷贝机制主要有以下几种 1.文件传输类DefaultF ...

随机推荐

  1. Android Studio 安装与设置

    http://www.cnblogs.com/abao0/p/6934127.html

  2. datasnap isapi程序iis设置

    datasnap isapi程序iis设置 添加ISAPI和CGI限制: 处理程序映射---添加模块映射: IIS应用程序池要如下设置: 停止ISAPI部署服务

  3. SharePoint PowerShell 修改母版页

    前言 最近在群里帮忙回答问题,碰到这么一个尴尬的问题,有人创建了一个新母版页,然后引用了新的母版页,不知道怎么的母版页有问题了,再也进不去站点了,希望修改回旧的母版页. 看到问题,想了一下,其实两种方 ...

  4. SharePoint 前端开发常用的对象之_spPageContextInfo

    前言 _spPageContextInfo对象,是SharePoint开发一个非常常用的对象,尤其是前端开发,可以非常方便的获取到一些和站点有关的信息. 完整对象如下图,需要什么属性,可以自己获取,然 ...

  5. 如何用Python计算Softmax?

    Softmax函数,或称归一化指数函数,它能将一个含任意实数的K维向量z"压缩"到另一个K维实向量\(\sigma{(z)}\)中,使得每一个元素的范围都在(0,1)之间,并且所有 ...

  6. 采石厂管理系统V3.0版本上线(采石厂车辆出入管理系统,石厂开票系统)

    新版系统包含老版所有功能,软件基础功能请点击查看<采石管理系统,采石厂车辆出入管理系统> 新增功能点 近期对采石厂管理系统进行了升级和完善,系统更加灵活好用,应用场景更加广泛.主要更新一下 ...

  7. 高仿MT4行情终端(K线图+操控+简单架构)

    技术:VS2015 Update3 + QT 5.11.2 + BOOST 1.68 + QT VS Tools + C++11   概述 模仿外汇MT4的界面 详细 代码下载:http://www. ...

  8. OpenLayers WorkShop 快速学习通道

    学习地址:https://openlayers.org/workshop/en/ OpenLayers Workshop Introduction Basics Creating a map Zoom ...

  9. 【微信小程序项目实践总结】30分钟从陌生到熟悉 web app 、native app、hybrid app比较 30分钟ES6从陌生到熟悉 【原创】浅谈内存泄露 HTML5 五子棋 - JS/Canvas 游戏 meta 详解,html5 meta 标签日常设置 C#中回滚TransactionScope的使用方法和原理

    [微信小程序项目实践总结]30分钟从陌生到熟悉 前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05- ...

  10. 深入理解Linux内存分配

    深入理解Linux内存分配 为了写一个用户层程序,你也许会声明一个全局变量,这个全局变量可能是一个int类型也可能是一个数组,而声明之后你有可能会先初始化它,也有可能放在之后用到它的时候再初始化.除此 ...