1. splice函数

#include <fcntl.h>
    ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);

splice用于在两个文件描述符之间移动数据, 也是零拷贝。

fd_in参数是待输入描述符。如果它是一个管道文件描述符,则off_in必须设置为NULL;否则off_in表示从输入数据流的何处开始读取,此时若为NULL,则从输入数据流的当前偏移位置读入。

fd_out/off_out与上述相同,不过是用于输出。

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

flags参数则控制数据如何移动:

SPLICE_F_NONBLOCK:splice 操作不会被阻塞。然而,如果文件描述符没有被设置为不可被阻塞方式的 I/O ,那么调用 splice 有可能仍然被阻塞。
    SPLICE_F_MORE:告知操作系统内核下一个 splice 系统调用将会有更多的数据传来。
    SPLICE_F_MOVE:如果输出是文件,这个值则会使得操作系统内核尝试从输入管道缓冲区直接将数据读入到输出地址空间,这个数据传输过程没有任何数据拷贝操作发生。

2. 使用splice时, fd_in和fd_out中必须至少有一个是管道文件描述符。

调用成功时返回移动的字节数量;它可能返回0,表示没有数据需要移动,这通常发生在从管道中读数据时而该管道没有被写入的时候。

失败时返回-1,并设置errno

3. 代码:通过splice将客户端的内容读入到管道中, 再从管道中读出到客户端,从而实现高效简单的回显服务。整个过程未执行recv/send,因此也未涉及用户空间到内核空间的数据拷贝。

//使用splice实现的回显服务器
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <assert.h>
    #include <errno.h>
    #include <string.h>
    #include <fcntl.h>
     
     
    int main(int argc, char **argv)
    {
     
        if (argc <= 2) {
            printf("usage: %s ip port\n", basename(argv[0]));
            return 1;
        }
        
        const char *ip = argv[1];
        int port = atoi(argv[2]);
     
        struct sockaddr_in address;
        bzero(&address, sizeof(address));
        address.sin_family = AF_INET;
        address.sin_port = htons(port);
        inet_pton(AF_INET, ip, &address.sin_addr);
     
        int sock = socket(PF_INET, SOCK_STREAM, 0);
        assert(sock >= 0);
        
        int reuse = 1;
        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
     
        int ret = bind(sock, (struct sockaddr*)&address, sizeof(address));
        assert(ret != -1);
     
        ret = listen(sock, 5);
        assert(ret != -1);
        
        struct sockaddr_in client;
        socklen_t client_addrlength = sizeof(client);
        
        int connfd = accept(sock, (struct sockaddr*)&client, &client_addrlength);
        if (connfd < 0) {
            printf("errno is: %s\n", strerror(errno));
        }
        else {
            int pipefd[2];
                    
            ret = pipe(pipefd);  //创建管道
            assert(ret != -1);
            
                    //将connfd上的客户端数据定向到管道中
            ret = splice(connfd, NULL, pipefd[1], NULL,
                            32768, SPLICE_F_MORE | SPLICE_F_MOVE);
            assert(ret != -1);
            
                    //将管道的输出定向到connfd上
            ret = splice(pipefd[0], NULL, connfd, NULL,
                            32768, SPLICE_F_MORE | SPLICE_F_MOVE);
            assert(ret != -1);                
            
            close(connfd);
        }
     
        
        close(sock);
     
     
     
     
        return 0;
    }

linux网络编程九:splice函数,高效的零拷贝相关推荐

  1. linux网络编程:splice函数和tee( )函数高效的零拷贝

    splice( )函数 在两个文件描述符之间移动数据,同sendfile( )函数一样,也是零拷贝.  函数原型: #include <fcntl.h> ssize_t splice(in ...

  2. Linux网络编程——Day12 两种高效的并发模式

    今天继续学习高性能服务器框架,上一篇关于高性能服务器的基础知识连接如下: Linux网络编程-Day11 高性能服务器程序框架_Jane_Librastar的博客-CSDN博客https://blog ...

  3. linux网络编程中listen函数 backlog的含义

    结论: backlog 是用来指定在TCP连接时,同时进行 3次握手建立连接的客户端数量 listen函数在一般在调用bind之后-调用accept之前调用, 它的函数原型是: #include< ...

  4. linux网络编程--数据结构与函数原型

    套接字有三种类型:流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM)及原始套接字. socket()    |  bind()    |                     ...

  5. linux网络编程常用函数详解与实例(socket--bind--listen--accept)

    常用的网络命令: netstat 命令netstat是用来显示网络的连接,路由表和接口统计等网络的信息.netstat有许多的选项我们常用的选项是 -an 用来显示详细的网络状态.至于其它的选项我们可 ...

  6. Linux C高级编程——网络编程之包裹函数

                                        Linux网络编程(六)--包裹函数                          宗旨:技术的学习是有限的,分享的精神是无 ...

  7. linux网络编程函数解析之——setsockopt / getsockopt用法

    linux网络编程函数解析之--setsockopt / getsockopt用法 工程中无线传输方面的东西用到了setsockopt(),getsockopt().网上相关博客很多,而且类似,原文出 ...

  8. Linux网络编程——黑马程序员笔记

    01P-复习-Linux网络编程 02P-信号量生产者复习 03P-协议 协议: 一组规则. 04P-7层模型和4层模型及代表协议 分层模型结构: OSI七层模型: 物.数.网.传.会.表.应TCP/ ...

  9. Linux网络编程---I/O复用模型之epoll

    https://blog.csdn.net/men_wen/article/details/53456474 Linux网络编程-I/O复用模型之epoll 1. epoll模型简介 epoll是Li ...

最新文章

  1. PXE批量部署linux操作系统
  2. emoji表情 与 iconfont 一锅炖
  3. springboot不会运行gc_SpringBoot项目深度优化和Jvm调优
  4. web操作系统开发的_哪种操作系统更适合Web开发
  5. 阿里、京东高级算法专家讲述数学在企业中的应用
  6. python输入一个整数列表 列表元素为18_Python-18 (高级变量1--列表)
  7. python并发编程6-协程
  8. JVM整体架构与调优参数说明
  9. 持续集成部署Jenkins工作笔记0006---运行Jenkins主体程序并初始化
  10. react 解决 setState 异步问题
  11. bzoj 1024 SCOI2009 生日快乐
  12. IOS 学习笔记 2015-04-10 OC-常用常量
  13. 基于SQL Server CE的移动服务系统开发
  14. excel大学计算机试题,大学计算机一级excel部分试题
  15. 手把手搭个vue的脚手架 - 2. 模板搭建
  16. 财务数据人一定要懂的分析方法——杜邦分析法
  17. stm32串口通信实验
  18. javascript 高级程序设计(第三版)读后归纳
  19. 详细了解步进电机的最大静转矩以及矩频特性
  20. 抛物线与双曲线、抛物面与锥面

热门文章

  1. 深入研究Clang(四) Clang编译器的简单分析
  2. tfw文件如何导入cad_如何将CAD的线稿导入PS并和底色分离
  3. 计算机公共基础知识教材,国家计算机二级考试公共基础知识教材
  4. python常用函数中文_【python】python常用函数
  5. android活动开始,android – 点击谷歌地图标记infoWindow开始活动
  6. 煮饭的机器人作文_公示|“笔随我心、心由笔动”作文大赛获奖名单
  7. oracle走当前时间分区,Oracle分区使用波斯日历的时间间隔
  8. java编译找不到符号_javac编译时找不到符号?
  9. STM32F1笔记(十二)DAC
  10. GDB与远程(交叉)GDB调试