文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

好玩的Sendfile---探索Node.Js中更快的数据传输方式

2024-12-03 05:07

关注

本文转载自微信公众号「编程杂技」,作者theanarkh。转载本文请联系编程杂技公众号。

在Node.js中,当我们给前端返回一个静态文件的时候,我们通常会把文件先读进内容,然后通过socket接口写到底层,从而返回给前端。无论是一次性读取到内存还是使用流式的方式,都不可避免地要把数据从内核复制到用户层,再把数据复制到内核,这是一种低效的方式,因为多了无效的复制。在nginx中,可以通过sendfile指令提供效率。Node.js的copyFile底层使用了sendfile系统调用,但是网络IO的时候,没有使用该API。因为Node.js通过队列的方式,控制数据的写入。那么是否可以实现sendfile的方式来提供这网络IO的效率。首先我们看一下sendfile的好处是什么。

我们看到sendfile通过把内核完成数据的传输,减少了内核和用户层的数据复制,从而提高了效率。下面我们通过napi写一个addon来实现这个功能。

  1. #include   
  2. #include   
  3. #include  
  4. #include  
  5. #include  
  6. static napi_value copyFile(napi_env env, napi_callback_info info) { 
  7.   size_t argc = 3; 
  8.   napi_value args[3]; 
  9.   // 拿到js层的入参,这里是三个 
  10.   napi_get_cb_info(env, info, &argc, args, NULLNULL); 
  11.   int fd1; 
  12.   int fd2; 
  13.   int len; 
  14.   // js传入的是一个数字,v8转成了对象,这里再次把入参转成int型 
  15.   napi_get_value_int32(env, args[0], &fd1); 
  16.   napi_get_value_int32(env, args[1], &fd2); 
  17.   napi_get_value_int32(env, args[2], &len); 
  18.   int writed = sendfile(fd2, fd1, 0,len); 
  19.   napi_value ret; 
  20.   napi_create_int32(env, writed, &ret); 
  21.   return ret; 
  22.  
  23. napi_value Init(napi_env env, napi_value exports) { 
  24.   napi_value func; 
  25.   // 创建一个函数并且设置为exports对象的getArray属性的值 
  26.   napi_create_function(env, 
  27.                       NULL
  28.                       NAPI_AUTO_LENGTH, 
  29.                       copyFile, 
  30.                       NULL
  31.                       &func); 
  32.   napi_set_named_property(env, exports, "copyFile", func); 
  33.   return exports; 
  34. NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 

下面我们看看怎么使用。首先用这个addon来复制文件,类似Node.js的copyyFile

  1. const fs= require('fs'); 
  2. const { copyFile } = require('./build/Release/sendfile.node'); 
  3. const { 
  4.   O_WRONLY, 
  5.   O_CREAT, 
  6. } = fs.constants; 
  7. async function test() { 
  8.   const [fd1, fd2] = await Promise.all([openFile('1.txt''r'), openFile('2.txt', O_WRONLY | O_CREAT)]); 
  9.   const { size } = await getFileInfo(fd1); 
  10.   console.log(copyFile(fd1, fd2, size)); 
  11.   fs.close(fd1, () => {}); 
  12.   fs.close(fd2, () => {}); 
  13. function openFile(filename, mode) { 
  14.   return new Promise((resolve, reject) => { 
  15.     fs.open(filename, mode, (err, fd) => { 
  16.       if (err) { 
  17.         reject(err); 
  18.       } else { 
  19.         resolve(fd); 
  20.       } 
  21.     }); 
  22.   })} 
  23.  
  24. function getFileInfo(fd) { 
  25.   return new Promise((resolve, reject) => { 
  26.     fs.fstat(fd, (err, stat) => { 
  27.       if (err) { 
  28.         reject(err) 
  29.       }else { 
  30.         resolve(stat); 
  31.       } 
  32.     }); 
  33.   }) 
  34. test(); 

执行上面代码,我们可以看到文件会成功复制2.txt。接着我们再来试一下网络IO的场景。

  1. const fs= require('fs'); 
  2. const http = require('http'); 
  3. const { copyFile } = require('./build/Release/sendfile.node'); 
  4. const server = http.createServer(async (req, res) => { 
  5.   const fd = await openFile('1.txt''r'); 
  6.   const { size } = await getFileInfo(fd); 
  7.   const ret = copyFile(fd, res.socket._handle.fd, size); 
  8.   res.socket.end(); 
  9. }).listen(8002); 
  10.  
  11. const { 
  12.   O_WRONLY, 
  13.   O_CREAT, 
  14. } = fs.constants; 
  15.  
  16. function openFile(filename, mode) { 
  17.   return new Promise((resolve, reject) => { 
  18.     fs.open(filename, mode, (err, fd) => { 
  19.       if (err) { 
  20.         reject(err); 
  21.       } else { 
  22.         resolve(fd); 
  23.       } 
  24.     }); 
  25.   })} 
  26.  
  27. function getFileInfo(fd) { 
  28.   return new Promise((resolve, reject) => { 
  29.     fs.fstat(fd, (err, stat) => { 
  30.       if (err) { 
  31.         reject(err) 
  32.       }else { 
  33.         resolve(stat); 
  34.       } 
  35.     }); 
  36.   })} 

以上代码首先启动一个http服务器,然后收到请求的时候,通过addon调用sendfile给前端返回对应的内容,最后关闭连接。结果如下。

 

sendfile似乎在网络IO中可以应用了,但只是一个demo的思路,后续有时间继续研究分析。

 

来源:编程杂技内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯