高级I/O函数之sendfile函数[通俗易懂]

高级I/O函数之sendfile函数[通俗易懂]sendfile函数在两个文件描述符之间传递数据(完全在内核中操作),从而避免了内核缓冲区和用户缓冲区之间的数据拷贝,效率很高,被称为零拷贝。函数定义为:#include<sys/sendfile.h>ssize_tsenfile(intout_fd,intin_fd,off_t*offset,size_tcount);in_fd参数是待读出内容的文件描述符,out…

大家好,又见面了,我是你们的朋友全栈君。

sendfile函数在两个文件描述符之间传递数据(完全在内核中操作),从而避免了内核缓冲区和用户缓冲区之间的数据拷贝,效率很高,被称为零拷贝。函数定义为:

#include<sys/sendfile.h>
ssize_t senfile(int out_fd,int in_fd,off_t* offset,size_t count);

in_fd参数是待读出内容的文件描述符,out_fd参数是待写入内容的文件描述符。offset参数指定从读入文件流的哪个位置开始读,如果为空,则使用读入文件流默认的起始位置。count参数指定文件描述符in_fd和out_fd之间传输的字节数。

in_fd必须是一个支持类似mmap函数的文件描述符,即它必须指向真实的文件,不能是socket和管道,而out_fd必须是一个socket

首先我们来看看传统的read/write方式进行socket的传输。
当需要对一个文件进行传输的时候,具体流程细节如下:

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

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

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

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

在这个过程中发生了四次copy操作。

硬盘->内核->用户->socket缓冲区(内核)->协议引擎。

而sendfile的工作原理呢??

1、系统调用 sendfile() 通过 DMA 把硬盘数据拷贝到 kernel buffer,然后数据被 kernel 直接拷贝到另外一个与 socket 相关的 kernel buffer。这里没有 用户态和核心态 之间的切换,在内核中直接完成了从一个 buffer 到另一个 buffer 的拷贝。
2、DMA 把数据从 kernel buffer 直接拷贝给协议栈,没有切换,也不需要数据从用户态和核心态,因为数据就在 kernel 里。

测试代码:

#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
#include<assert.h>
#include<stdio.h>
#include<string.h>
#include<sys/sendfile.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<errno.h>

int main(int argc,char *argv[])
{
    if(argc<=3)
    {
        printf("usage:%s ip_address port_number filename\n",basename(argv[0]));
        return 1;
    }
    const char* ip = argv[1];
    int port = atoi(argv[2]);
    const char* file_name = argv[3];

    int filefd = open(file_name,O_RDONLY);
    assert(filefd>0);

    struct stat stat_buf;
    fstat(filefd,&stat_buf);

    struct sockaddr_in address;

    bzero(&address,sizeof(address));
    address.sin_family = AF_INET;
    inet_pton(AF_INET,ip,&address.sin_addr);
    address.sin_port = htons(port);

    int sock = socket(PF_INET,SOCK_STREAM,0);
    assert(sock>=0);

    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 %d\n",errno);
    }
    else 
    {
        sendfile(connfd,filefd,NULL,stat_buf.st_size);
        close(connfd);
    }
    close(sock);
    return 0;
}

然后进行
这里写图片描述

在另外一个虚拟机上telnet

这里写图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/143051.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • hasOwnproperty详细总结

    hasOwnproperty详细总结hasOwnProperty:是用来判断一个对象是否有你给出名称的属性或对象。不过需要注意的是,此方法无法检查该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员。isPrototypeOf:是用来判断要检查其原型链的对象是否存在于指定对象实例中,是则返回true,否则返回falsefunctionperson(nickName,siteName){…

    2025年5月23日
    4
  • PLD- FPGA与CPLD的区别[通俗易懂]

    PLD- FPGA与CPLD的区别[通俗易懂]http://home.eeworld.com.cn/my/space.php?uid=170289&do=blog&id=31215FPGA与CPLD的区别多篇整合系统的比较,与大家共享:尽管FPGA和CPLD都是可编程ASIC器件,有很多共同特点,但由于CPLD和FPGA结构上的差异,具有各自的特点:①CPLD更适合完成各种算法和组合逻辑,FPGA更适合于完成时序逻辑

    2022年5月27日
    37
  • python激活码2021【2021最新】

    (python激活码2021)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.htmlMLZPB5EL5Q-eyJsaWN…

    2022年3月20日
    47
  • spidermonkey学习

    spidermonkey学习JavaScript在浏览器中的应用几乎是尽人皆知的。实际上,JavaScript技术也可以使用在非浏览器应用程序当中,从而让应用程序具有自动的脚本功能。本文介绍了一种功能非常强大的JavaScript引擎SpiderMonkey。这个引擎是Mozilla浏览器的JavaScript引擎。该引擎接口定义清晰,模块化好。本文简要介绍了SpiderMonkey的基本结构,并讲解了如何在自己的应用

    2022年10月16日
    2
  • uu怎么卸载_卸载deepin引导

    uu怎么卸载_卸载deepin引导ubutun干净卸载删除wineQQ博主原本想要在ubuntu18.04安装wineQQ,在安装完成后却显示QQ版本过低无法运行,只能卸载重装,不然那个QQ标志在软件列表非常碍眼。这个是之前安装wineQQ的教程【QQ版本已过期】问题:卸载不掉该软件且网上大多数指令都过期了解决方案:在deepinwine的应用容器中,用sudoaptremove软件包主名命令来删除。比如d…

    2025年9月19日
    6
  • python中unittest框架_unittest框架原理

    python中unittest框架_unittest框架原理unittest简介参考:https://urlify.cn/e6rAr2为什么要使用unittest在编写接口自动化用例时,我们一般针对一个接口建立一个.py文件,一条测试用例封装为一个函数(方法),但是在批量执行的过程中,如果其中一条出错,后面的用例就无法执行。使用测试框架可以互不影响的用例执行及更灵活的执行控制。unittest特点 •python自带的单元测试框架,无需安装; •用例执行互不干扰; •提供不同范围的setUp(测试准备)和t..

    2022年10月10日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号