初探sendfile「建议收藏」

初探sendfile「建议收藏」很早就知道sendfile这个专门用来传输大文件的函数,也称为零拷贝,但一直没测试过,今天用了宿舍的网和小组内的网测试了下,发现结果和我预想的不一样。为什么效率高,网上说的也很多了,看下man手册中的内容sendfile()copiesdatabetweenonefiledescriptorandanother.Becausethiscopyingisdo

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

很早就知道sendfile这个专门用来传输大文件的函数,也称为零拷贝,但一直没测试过,今天用了宿舍的网和小组内的网测试了下,发现结果和我预想的不一样。


为什么效率高,网上说的也很多了,看下man手册中的内容
sendfile() copies data between one file descriptor and another. Because this copying is done within the kernel, sendfile() is more efficient than the combination of read(2) and write(2), which would require transferring data to and from user space.
普通的read和write先会将数据拷贝到用户空间,然后再拷贝到内核空间,然后从tcp缓冲区发送出去。sendfile避免了多余的拷贝。


测试过程:

通过hdparm -Tt /dev/sda
测试了我的磁盘IO大约是110MB/sec

通过bmon
宿舍网大概150k/s,小组内网大概4.5~5.5MB/s。
只是测试了个大概。参考而已

服务端跑在学长借我的服务器上测试。


数据有限,我测试的分别为7.5M,90M,2G的数据。
起初宿舍网络有点慢,read,write版本和sendfile版本运行出来的时间都几乎差不多。然后我在小组测试网速4.5~5.5MB/s,跑出来的数据竟然也差不多,有时read,write版本竟然比sendfile版本的时间短
很奇怪,最后一想,磁盘IO的性能依然是远大于网络IO的性能,我测试的两种网络带宽远远不够。


测试结论:

最后询问了学长,得知4.5mb/s-5.5mb/s也就是带宽为36-44mib/s的网络IO是远远不够的,用ifconfig查看本机ip来测试,本机千兆网卡测试出来传送2.2G数据sendfile效率的确高于read,write。
那么像我们普通这种网络带宽根本不能满足且突出sendfile的性能。


测试代码:客户端

客户端两个版本,一个为read,write,一个为sendfile,修改注释即可

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/sendfile.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char *argv[])
{
    if(argc < 3){
        printf("argument error\n");
        exit(1);
    }
    char *ip = argv[1];
    int port = atoi(argv[2]);

    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    inet_pton(AF_INET, ip, &server.sin_addr);

    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if(fd < 0){
        printf("create socket error\n");
        exit(1);
    }
    int con_ret = connect(fd, (struct sockaddr*)&server, sizeof(server));
    if(con_ret == -1){
        printf("connect error\n");
        exit(1);
    }
    char *name = argv[3];
    int r_fd = open(name, O_RDONLY);
    if(r_fd == -1){
        printf("open file error\n");
        exit(1);
    }
    struct stat st;
    long int size = stat(name, &st);
    if(size < 0){
        printf("file stat error\n");
        exit(1);
    }
    printf("file size:%ld\n", st.st_size);
    off_t pos = lseek(r_fd, 0, SEEK_SET);
    if(pos < 0){
        printf("obtain fileP error\n");
        exit(1);
    }
    char *cname = "newfile";
    int sn = send(fd, cname, sizeof(argv[3]), 0);
    struct timeval startTime, endTime;
    double timeuse;
    gettimeofday(&startTime, NULL);
    //sendfile测试版本
    //int n = sendfile(fd, r_fd, &pos, st.st_size);
    long int ssize = 0;
    char buffer[2048];
    long int n = 0;
    //read,write测试版本
    while(1){
        bzero(buffer, 2048);
        int rn = read(r_fd, buffer, 2048);
        int wn = write(fd, buffer, 2048);
        if(n >= st.st_size){
            printf("size:%ld\n", n);
            printf("size:%ld\n", st.st_size);
            break;
        }
        n += rn;
    }
    gettimeofday(&endTime, NULL);
    timeuse = 1000000*(endTime.tv_sec - startTime.tv_sec) + (endTime.tv_usec - startTime.tv_usec);
    timeuse /= 1000000;
    printf("timeuse = %lf\n", timeuse);
    if(n == -1){
        printf("send file error\n");
        exit(1);
    }

    return EXIT_SUCCESS;
}

测试代码:服务器

服务端测试代码不变

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char *argv[])
{
    if(argc < 2){
        printf("argument error\n");
        exit(1);
    }
    char *ip = argv[1];
    int port = atoi(argv[2]);

    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    inet_pton(AF_INET, ip, &server.sin_addr);

    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if(fd < 0){
        printf("create socket error\n");
        exit(1);
    }
    int b_ret = bind(fd, (struct sockaddr*)&server, sizeof(server));
    if(b_ret == -1){
        printf("bind error\n");
        exit(1);
    }
    int l_ret = listen(fd, 64);
    if(l_ret == -1){
        printf("listen error\n");
        exit(1);
    }
    socklen_t len = sizeof(server);
    int sockfd = accept(fd, (struct sockaddr*)&server, &len);
    if(sockfd == -1){
        printf("accept error\n");
        exit(1);
    }else{
        printf("connect success\n");
    }
    char name[128];
    char buffer[2048];
    bzero(name, 128);
    bzero(buffer, 2048);
    int n = recv(sockfd, name, 2048, 0);
    if(n <= 0){
        printf("recv error\n");
        exit(1);
    }
    printf("name:%s\n", name);
    int w_fd = open(name, O_WRONLY | O_CREAT, 777);
    if(w_fd == -1){
        printf("open file error\n");
        exit(1);
    }
    off_t pos = lseek(w_fd, 0, SEEK_CUR);
    if(pos < 0){
        printf("obtain file pointer error\n");
        exit(1);
    }
    while(1){
        bzero(buffer, 2048);
        int n = recv(sockfd, buffer, 2048, 0);
        if(n < 0){
            printf("recv error\n");
            exit(1);
        }else if(n == 0){
            break;
        }
        ssize_t s_t = write(w_fd, buffer, n);
        if(s_t < 0){
            printf("write error\n");
            exit(1);
        }
    }
    printf("recv file success!!!\n");


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

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

(0)
上一篇 2022年6月6日 上午9:16
下一篇 2022年6月6日 上午9:36


相关推荐

  • Android 代码混淆机制

    Android 代码混淆机制Android代码混淆机制由于Android项目大部分用的java语言,而java属于高层抽象语言,易于反编译、反汇编,其编译后的程序包包含了大量的源代码变量、函数名、数据结构等信息,根据其编译打包后的APK文件,可以非常容易的得到近乎源代码质量的反编译代码。如果不加混淆,相当于直接将源代码拱手送人,内容严密的app权限审核可以说是形同虚设。如果大家想避免源代码泄漏后重新修改策划而额外增加的工

    2022年5月30日
    82
  • linux文件权限754表示,Linux命令chmod修改文件权限 777和754方法

    linux文件权限754表示,Linux命令chmod修改文件权限 777和754方法在 linux 操作系统下 使用 shell 命令来操作 常用下面这条命令 chmod777 文件或目录示例 chmod777 etc squid 运行命令后 squid 文件夹 目录 的权限就被修改为 777 可读可写可执行 如果是 Ubuntu 系统 可能需要加上 sudo 来执行 sudochmod777 etc squidLinux 系统中 每个用户的角色和权限划分的很细致也很严格 每个文件

    2026年3月26日
    2
  • mysql 创建联合索引_数据库怎么创建索引

    mysql 创建联合索引_数据库怎么创建索引CREATETABLE`test`( ‘aaa’VARCHAR(16)NOTNULLDEFAULT”, ‘bbb’VARCHAR(16)NOTNULLDEFAULT”, ‘ccc’INT(11)UNSIGNEDNOTNULLDEFAULT0, KEY`sindex`(`aaa`,`bbb`,`ccc`))ENGINE=MyISAMCO…

    2025年8月30日
    5
  • idea在线激活服务器(在线激活)

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

    2022年3月14日
    828
  • BP神经网络原理推导

    BP神经网络原理推导本文会完成BP神经网络的推导过程,先介绍BP神经网络的历史,然后介绍BP神经网络的结构,然后再开始推导,最后介绍BP神经网络的优缺点以及几个优化的方法。

    2022年7月20日
    15
  • Java 类型信息详解和反射机制

    Java 类型信息详解和反射机制

    2020年11月19日
    209

发表回复

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

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