首页 > 代码库 > 高级I/O函数(2)-splice函数
高级I/O函数(2)-splice函数
splice函数:
功能描述:用于在两个文件描述符之间移动数据,也是零拷贝操作。函数定义如下:
1 #include <fcntl.h>3 ssize_t splice(int fd_in,loff_t* off_t,int fd_out,loff_t* off_out,size_t len,unsigned int flags);
参数描述:
fd_in:待输入数据的文件描述符.
off_t:如果fd_in是一个管道文件描述符,那么off_t参数必须是NULL,表示从数据流的当前偏移位置读入;如果fd_in不是一个管道文件描述符(例如socket),则它将指出具体的偏移位置.
len:指定移动数据的长度.
flags:则控制数据如何移动,它可以被设置为下表中值的按位异或.
表 splice的flags参数的常用取值及其含义
常用值 | 含义 |
SPLICE_F_MOVE | 如果合适的话,按整页内存移动数据. |
SPLICE_F_NONBLOCK | 非阻塞的splice操作,但实际效果还是会受文件描述符本身的阻塞状态的影响. |
SPLICE_F_MORE | 给内核一个提示:后续的splice调用将读取更多的数据 |
SPLICE_F_GIFT | 对splice没有效果. |
注意:
使用splice函数时,fd_in和fd_out必须至少有一个管道文件描述符.调用成功后返回移动字节的数量.它可能返回0,这发生从管道中读取数据时而该管道没有被写入任何数据.错误返回-1并设置errno.
例子:利用splice函数来实现一个零拷贝的回射服务器模型。
1 #include <sys/socket.h> 2 #include <netinet/in.h> 3 #include <arpa/inet.h> 4 #include <unistd.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <fcntl.h> 8 9 int main(int argc,const char* argv[]){10 if(argc!=2){11 printf("usage:%s ip_address port_number\n",argv[0]);12 return -1;13 }‘14 15 const char* ip=argv[1];16 int port=atoi(argv[2]);17 18 int ret;19 struct sockaddr_in address;20 bzero(&address,sizeof(address));21 address.sin_family=AF_INET;22 inet_pton(AF_INET,ip,&address.sin_addr);23 address.sin_port=htons(port);24 25 int sockfd=socket(AF_INET,SOCK_STREAM,0);26 assert(sockfd!=-1);27 28 ret=bind(sockfd,(struct sockaddr*)&address,sizeof(address));29 assert(ret!=-1);30 31 ret=listen(sockfd,5);32 assert(ret!=-1);33 34 while(1){35 struct sockaddr_in peer;36 bzero(&peer,sizeof(peer));37 socklen_t len=sizeof(peer);38 39 int connfd=accept(sockfd,(struct sockaddr*)&peer,len);40 if(connfd<0){41 printf("errno is:%d\n",errno);42 break;43 }44 else{45 int pipefd[2];46 ret=pipe(pipefd);47 assert(ret!=-1);48 49 /*将connfd上流入的客户端数据定向到管道中*/50 ret=splice(connfd,NULL,pipefd[1],NULL,32768,SPLICE_F_MORE|51 SPLICE_F_MOVE);52 assert(ret!=-1);53 /*将管道中的数据定向到connfd的客户端文件描述符上*/54 splice(pipefd[0],NULL,connfd,NULL,32768,SPLICE_F_MORE|55 SPLICE_F_MOVE);56 assert(ret!=-1);57 } 58 }59 60 close(connfd);61 close(sockfd);62 return 0;63 }
我们通过splice函数将从客户端的内容读入到pipefd[1]中,然后再使用splice函数从pipefd[0]中读出该内容到客户端。从而实现了简单高效的回射服务。整个过程为执行recv/send操作,因此未涉及用户空间和内核空间之间的数据拷贝。
高级I/O函数(2)-splice函数
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。