Sendfile函数说明

#include
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

sendfile()是作用于数据拷贝在两个文件描述符之间的操作函数.这个拷贝操作是内核中操作的,所以称为"零拷贝".sendfile函数比起read和write函数高效得多,因为read和write是要把数据拷贝到用户应用层操作.

参数说明:
out_fd 是已经打开了,用于写操作(write)的文件描述符;
in_fd 是已经打开了,用于读操作(read)的文件描述符;
offset 偏移量;表示sendfile函数从in_fd中的哪一偏移量开始读取数据.如果是零表示从文件的开始读,否则从相应的便宜量读取.如果是循环读取的时候,下一次offset值应为sendfile函数返回值加上本次的offset的值.
count是在两个描述符之间拷贝的字节数(bytes)

返回值:
如果成功的拷贝,返回写操作到out_fd的字节数,错误返回-1,并相应的设置error信息.

EAGAIN 无阻塞I/O设置O_NONBLOCK时,写操作(write)阻塞了.
EBADF 输出或者输入的文件描述符没有打开.
EFAULT 错误的地址.
EINVAL 描述符不可用或者锁定了,或者用mmap()函数操作的in_fd不可用.
EIO 当读取(read)in_fd时发生未知错误.
ENOMEM 读(read)in_fd时内存不足.

由于想再提升原有系统中文件传输模块的速度,并减少系统资源占用,进行了一次sendfile()的性能测试,但失败了.不过还是将它用在了模块中.记录一下这次失改的微调测试.

运行平台: 客户机与服务器均为P4计算机,IDE硬盘; Fedora5发行版; 百兆局域网;

接收端程序如下:

FILE *fp = fopen(FILENAME,"wb");

while((len = recv(sockfd, buff, sizeof(buff), 0)) > 0)
{
fwrite(buffer, 1, len, fp);
}
fclose(fp);

A. 发送端传统方式代码段如下:

fd = open(FILENAME, O_RDONLY);
while((len =read(fd, buff, sizeof(buff))) >0)
{
send(sockfd, buff, len ,0);
}
close(fd);

由于我磁盘分区时指定的块大小为4096,为了最优读取磁盘数据,buff大小设为4096字节.但在测试中发现设为1024或8192不会对传输速度带来影响.

文件大小:9M; 耗时:0.71 - 0.76秒;
文件大小:32M; 耗时:2.64 - 2.68秒;
文件大小:64M; 耗时:5.36 - 5.43秒;

B. 使用sendfile()传输代码段.

off_t offset = 0;
stat(FILENAME, &filestat); fd = open(FILENAME, O_RDONLY);
sendfile(sockfd, fd, &offset, filestat.st_size) );
close(fd);

文件大小:9M; 耗时:0.71 - 1.08秒;
文件大小:32M; 耗时:2.66 - 2.74秒;
文件大小:64M; 耗时:5.43 - 6.64秒;

似乎还略有下降.根据sendfile的man手册,我在使用该函数前调用了

int no = 1;
printf("%d\n", setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, (char*)&no, sizeof(int)) );

文件大小:9M; 耗时:0.72 - 0.75秒;
文件大小:32M; 耗时:2.66 - 2.68秒;
文件大小:64M; 耗时:5.38 - 5.60秒;

这样似乎达到了传统方式的速度?!不管哪种环境下,我用ethereal抓包显示每一个tcp包的playload部分最大也通常是1448字节.

看来我的测试没有体现出"应用层数据的两次拷贝带来很大的消耗"这一说法.如果按照存在就是有理的说法的话,那我想sendfile()在两种情况下才体现优势,但我却没有环境测试:

1. 大并发量的文件服务器或HTTP服务器;
2. 内存资源紧张的嵌入式系统;

另外,网络上大量的关于tcp选项中的TCP_CORK描述已经过时.在man手册中早已提到该参数可以与TCP_NODELAY结合使用了.只是,只要设置了TCP_NODELAY选项后,不管是否设置TCP_CORK,包都会立即发出.

补充:
TCP_NODELAY和TCP_CORK基本上控制了包的“Nagle化”,Nagle化在这里的含义是采用Nagle算法把较小的包组装为更大的帧。 John Nagle是Nagle算法的发明人,后者就是用他的名字来命名的,他在1984年首次用这种方法来尝试解决福特汽车公司的网络拥塞问题(欲了解详情请参看IETF RFC 896)。他解决的问题就是所谓的silly window syndrome ,中文称“愚蠢窗口症候群”,具体含义是,因为普遍终端应用程序每产生一次击键操作就会发送一个包,而典型情况下一个包会拥有一个字节的数据载荷以及40个字节长的包头,于是产生4000%的过载,很轻易地就能令网络发生拥塞,。 Nagle化后来成了一种标准并且立即在因特网上得以实现。它现在已经成为缺省配置了,但在我们看来,有些场合下把这一选项关掉也是合乎需要的。

现在让我们假设某个应用程序发出了一个请求,希望发送小块数据。我们可以选择立即发送数据或者等待产生更多的数据然后再一次发送两种策略。如果我们马上发送数据,那么交互性的以及客户/服务器型的应用程序将极大地受益。例如,当我们正在发送一个较短的请求并且等候较大的响应时,相关过载与传输的数据总量相比就会比较低,而且,如果请求立即发出那么响应时间也会快一些。以上操作可以通过设置套接字的TCP_NODELAY选项来完成,这样就禁用了 Nagle算法。

另外一种情况则需要我们等到数据量达到最大时才通过网络一次发送全部数据,这种数据传输方式有益于大量数据的通信性能,典型的应用就是文件服务器。应用Nagle算法在这种情况下就会产生问题。但是,如果你正在发送大量数据,你可以设置TCP_CORK选项禁用Nagle化,其方式正好同 TCP_NODELAY相反(TCP_CORK 和 TCP_NODELAY 是互相排斥的)。下面就让我们仔细分析下其工作原理。

假设应用程序使用sendfile()函数来转移大量数据。应用协议通常要求发送某些信息来预先解释数据,这些信息其实就是报头内容。典型情况下报头很小,而且套接字上设置了TCP_NODELAY。有报头的包将被立即传输,在某些情况下(取决于内部的包计数器),因为这个包成功地被对方收到后需要请求对方确认。这样,大量数据的传输就会被推迟而且产生了不必要的网络流量交换。

但是,如果我们在套接字上设置了TCP_CORK(可以比喻为在管道上插入“塞子”)选项,具有报头的包就会填补大量的数据,所有的数据都根据大小自动地通过包传输出去。当数据传输完成时,最好取消TCP_CORK 选项设置给连接“拔去塞子”以便任一部分的帧都能发送出去。这同“塞住”网络连接同等重要。

总而言之,如果你肯定能一起发送多个数据集合(例如HTTP响应的头和正文),那么我们建议你设置TCP_CORK选项,这样在这些数据之间不存在延迟。能极大地有益于WWW、FTP以及文件服务器的性能,同时也简化了你的工作。

from:http://www.linuxdiyf.com/viewarticle.php?id=69189

Linux "零拷贝" sendfile函数中文说明及实际操作分析的更多相关文章

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

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

  2. Linux零拷贝原理

    Linux零拷贝原理 前言 磁盘可以说是计算机系统最慢的硬件之一,读写速度相差内存 10 倍以上,所以针对优化磁盘的技术非常的多,比如零拷贝.直接 I/O.异步 I/O 等等,这些优化的目的就是为了提 ...

  3. Netty 零拷贝(一)Linux 零拷贝

    Netty 零拷贝(一)Linux 零拷贝 本文探讨 Linux 中主要的几种零拷贝技术以及零拷贝技术适用的场景. 一.几个重要的概念 1.1 用户空间与内核空间 操作系统的核心是内核,独立于普通的应 ...

  4. NIO学习笔记,从Linux IO演化模型到Netty—— Linux零拷贝

    这里只是感性地认识Linux零拷贝,不涉及具体细节. 1.Linux传统的数据拷贝 用户进程是不能直接访问文件系统的,要先切换到内核态,发起系统调用,DMA把磁盘中的数据写入内核空间,内核再把数据拷贝 ...

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

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

  6. Linux零拷贝技术

    本文转载自Linux零拷贝技术 导语 本文讲解 Linux 的零拷贝技术,云计算是一门很庞大的技术学科,融合了很多技术,Linux 算是比较基础的技术,所以,学好 Linux 对于云计算的学习会有比较 ...

  7. Linux零拷贝技术 直接 io

    Linux零拷贝技术 .https://kknews.cc/code/2yeazxe.html   https://zhuanlan.zhihu.com/p/76640160 https://clou ...

  8. Linux 零拷贝技术

    简介 零拷贝(zero-copy)技术可以减少数据拷贝和共享总线操作的次数,消除通信数据在存储器之间不必要的中间拷贝过程,有效地提高通信效率,是设计高速接口通道.实现高速服务器和路由器的关键技术之一. ...

  9. 零拷贝sendfile解析

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

随机推荐

  1. 紫书 例题 10-26 UVa 11440(欧拉函数+数论)

    这里用到了一些数论知识 首先素因子都大于M等价与M! 互质 然后又因为当k与M!互质且k>M!时当且仅当k mod M! 与M!互质(欧几里得算法的原理) 又因为N>=M, 所以N!为M! ...

  2. [USACO15JAN]草鉴定Grass Cownoisseur(分层图+tarjan)

    [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of his cows ...

  3. PatentTips - Virtualizing performance counters

    BACKGROUND Generally, the concept of virtualization in information processing systems allows multipl ...

  4. 洛谷——P1019 单词接龙(NOIP2000 T3)

    https://www.luogu.org/problem/show?pid=1019#sub 题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母, ...

  5. Ubuntu14环境下minigui安装问题记录--object.lo错误

    minigui3.0.12在Ubuntu14上面编译只是去?出现这个错误:object.h:275:9: error: incompatible types when assigning to typ ...

  6. 暑假集训-WHUST 2015 Summer Contest #0.2

    ID Origin Title 10 / 55 Problem A Gym 100625A Administrative Difficulties   4 / 6 Problem B Gym 1006 ...

  7. 异常:error 0152: No Entity Framework provider found for the ADO.NET provider with invariant name 'System.Data.SqlClient'

    error 0152: No Entity Framework provider found for the ADO.NET provider with invariant name 'System. ...

  8. 图论:Tarjan算法

    在有向图中,若两点至少包含一条路径可以到达,则称两个顶点强连通,若任意两个顶点皆如此,则称此图为强联通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected com ...

  9. Innodb锁的类型

    Innodb锁的类型 行锁(record lock) 行锁总是对索引上锁,如果某个表没有定义索引,mysql就会使用默认创建的聚集索引,行锁有S锁和X锁两种类型. 共享锁和排它锁 Innodb锁有两种 ...

  10. python 发送邮件 <QQ+腾讯企业邮箱>

    一.使用QQ邮箱或者腾讯企业邮箱 python 发送邮件属于网络编程方向的,在工作中,我需要经常用邮件来检测我的程序运行状况.使用起来十分方便,这里我就用腾讯企业邮箱作为我的收发邮箱来使用. 使用py ...