高级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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Python解释器以及PyCharm的安装

    Python解释器以及PyCharm的安装通过CSDN上,大神写的教程,安装了PyCharm,现自己总结Python解释器安装以及PyCharm安装过程。一、Python解释器安装解释器(英语:Interpreter),又译为直译器,是一种电脑程序能够把高级编程语言一行一行直接转译运行。解释器不会一次把整个程序转译出来,只像一位“中间人”,每次运行程序时都要先转成另一种语言再作运行,因此解释器的程序运行速度比较缓慢。它每转译一行程序叙述就…

    2022年7月22日
    9
  • VMware16NAT模式配置固定IP[通俗易懂]

    VMware16NAT模式配置固定IP[通俗易懂]文章目录前言一、NAT配置固定IP二、重启网卡结尾前言为什么要配置固定IP呀?这个很容易解释啊,因为配置集群要设置固定IP(主结点需要管理子结点,通过固定IP识别机器),因为你访问虚拟机方便(不固定IP访问前还需要先查下虚拟机当前分配IP,比较麻烦)等等。配置固定IP采用哪种网络配置方式呢,NAT,桥接?仅主机反正是不行的,不能联网啊。NAT也叫网络地址转换,通常它的名称为VMnet8,通过nat的连接方式可以使得虚拟机和真实机的网卡在不同的网段中,从而实现联网。而bridge也叫桥接,通常它的名称

    2022年6月29日
    70
  • 物联网智能家居系统设计方案(想开一家智能产品店)

    物联网智能家居系统1.需求分析、原理/基础准备1.1实验目的1.2基本功能1.3模块功能描述1.3.1主功能函数模块1.3.2串口通信模块1.3.3电机模块1.3.4时间获取模块1.3.5温湿度光电模块1.3.6烟雾模块1.3.7PWM调光模块1.3.8灯泡模块2.概要设计说明2.1模块调用图3.详细设计说明(各部分成员分工部分)3.1主程序模块3.2通信模块3.3串口模块3.4PWM调光模…

    2022年4月12日
    30
  • wireshark抓包工具详细说明及操作使用_wireshark抓包结果分析

    wireshark抓包工具详细说明及操作使用_wireshark抓包结果分析多年之后,愿你有清风与烈酒,也有人是你的归途。打开Wireshark抓包工具开始抓包会看到如下展开内容:这里我是对wlan进行抓包,192.168.2.112是我当前wifi的ip地址。点击某个包,可以查看具体内容,差不多刚好对于五层协议:Frame:物理层的数据帧概况。EthernetII:数据链路层以太网帧头部信息。InternetProtocolVersion4:互联网层I

    2025年9月24日
    5
  • 人际关系处理技巧

    人际关系处理技巧

    2022年1月23日
    48
  • pychram激活码(破解版激活)

    pychram激活码(破解版激活),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月16日
    79

发表回复

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

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