您的位置:首页 > 运维架构 > Linux

【Linux编程】零拷贝之splice( )函数和tee( )函数

2015-12-10 00:18 1086 查看
关于零拷贝技术的相关文章,请参考:【Linux编程】大冒险之零拷贝技术探究

splice( )函数

在两个文件描述符之间移动数据,同sendfile( )函数一样,也是零拷贝。

函数原型:

#include <fcntl.h>
ssize_t splice(int fdin, loff_t *offin, int fdout, loff_t *offout, size_t len, unsigned int flags);


参数意义

fdin参数:待读取数据的文件描述符。

offin参数:指示从输入数据的何处开始读取,为NULL表示从当前位置。如果fdin是一个管道描述符,则offin必须为NULL。

fdout参数:待写入数据的文件描述符。

offout参数:同offin,不过用于输出数据。

len参数:指定移动数据的长度。

flags参数:表示控制数据如何移动,可以为以下值的按位或:

SPLICE_F_MOVE:按整页内存移动数据,存在bug,自内核2.6.21后,实际上没有效果。

SPLICE_F_NONBLOCK:非阻塞splice操作,实际会受文件描述符本身阻塞状态影响。

SPLICE_F_MORE:提示内核:后续splice将调用更多数据。

SPLICE_F_GIFT:对splice没有效果。

fdin和fdout必须至少有一个是管道文件描述符。

返回值

返回值>0:表示移动的字节数。

返回0:表示没有数据可以移动,如果从管道中读,表示管道中没有被写入数据。

返回-1;表示失败,并设置errno。

errno值如下

EBADF:描述符有错。

EINVAL:目标文件不支持splice,或者目标文件以追加方式打开,或者两个文件描述符都不是管道描述符。

ENOMEM:内存不够。

ESPIPE:某个参数是管道描述符,但其偏移不是NULL。

tee( )函数

在两个管道文件描述符之间复制数据,同是零拷贝。但它不消耗数据,数据被操作之后,仍然可以用于后续操作。

函数原型:

#include <fcntl.h>
ssize_t tee(int fdin, int fdout, size_t len, unsigned int flags);


参数意义

fdin参数:待读取数据的文件描述符。

fdout参数:待写入数据的文件描述符。

len参数:表示复制的数据的长度。

flags参数:同splice( )函数。

fdin和fdout必须都是管道文件描述符。

返回值

返回值>0:表示复制的字节数。

返回0:表示没有复制任何数据。

返回-1:表示失败,并设置errno。

代码实例:

/*splice()和tee()实现将文件"./1.txt"同时拷贝到文件"./2.txt"和"./3.txt"中*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

int main(){
int fd1 = open("./1.txt", O_RDONLY);
int fd2 = open("./2.txt", O_RDWR| O_CREAT | O_TRUNC, 0666);
int fd3 = open("./3.txt", O_RDWR| O_CREAT | O_TRUNC, 0666);

/*用于向"./2.txt"输入数据*/
int pipefd2[2];
/*用于向"./3.txt"输入数据*/
int pipefd3[2];
pipe(pipefd2);
pipe(pipefd3);

/*将fd1文件的内容输入管道pipefd2中*/
splice(fd1, NULL, pipefd2[1], NULL, 10086, SPLICE_F_MORE);
/*将管道pipefd2的内容复制到管道pipefd3中,不消耗管道pipefd2上的数据,管道pipefd2上的数据可以用于后续操作*/
tee(pipefd2[0], pipefd3[1], 10086, SPLICE_F_NONBLOCK);
/*将管道pipefd2的内容写入fd2文件中*/
splice(pipefd2[0], NULL, fd2, NULL, 10086, SPLICE_F_MORE);
/*将管道pipefd3的内容写入fd3文件中*/
splice(pipefd3[0], NULL, fd3, NULL, 10086, SPLICE_F_MORE);

close(fd1);
close(fd2);
close(fd3);
close(pipefd2[0]);
close(pipefd2[1]);
close(pipefd3[0]);
close(pipefd3[1]);
return 0;
}


为了简化操作,程序里省略了错误处理,实际编程中需要加入。

相关文件:

【Linux编程】大冒险之零拷贝技术探究
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息