Node.Js中更快的数据传输方式
更新:HHH   时间:2023-1-7


这篇文章主要介绍“Node.Js中更快的数据传输方式”,在日常操作中,相信很多人在Node.Js中更快的数据传输方式问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Node.Js中更快的数据传输方式”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

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

  • 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.

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

#include <sys/sendfile.h>  #include <stdio.h>  #include <unistd.h> #include <fcntl.h> #include <node_api.h> static napi_value copyFile(napi_env env, napi_callback_info info) {   size_t argc = 3;   napi_value args[3];   // 拿到js层的入参,这里是三个   napi_get_cb_info(env, info, &argc, args, NULL, NULL);   int fd1;   int fd2;   int len;   // js传入的是一个数字,v8转成了对象,这里再次把入参转成int型   napi_get_value_int32(env, args[0], &fd1);   napi_get_value_int32(env, args[1], &fd2);   napi_get_value_int32(env, args[2], &len);   int writed = sendfile(fd2, fd1, 0,len);   napi_value ret;   napi_create_int32(env, writed, &ret);   return ret; }  napi_value Init(napi_env env, napi_value exports) {   napi_value func;   // 创建一个函数并且设置为exports对象的getArray属性的值   napi_create_function(env,                       NULL,                       NAPI_AUTO_LENGTH,                       copyFile,                       NULL,                       &func);   napi_set_named_property(env, exports, "copyFile", func);   return exports; } NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

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

const fs= require('fs'); const { copyFile } = require('./build/Release/sendfile.node'); const {   O_WRONLY,   O_CREAT, } = fs.constants; async function test() {   const [fd1, fd2] = await Promise.all([openFile('1.txt', 'r'), openFile('2.txt', O_WRONLY | O_CREAT)]);   const { size } = await getFileInfo(fd1);   console.log(copyFile(fd1, fd2, size));   fs.close(fd1, () => {});   fs.close(fd2, () => {}); } function openFile(filename, mode) {   return new Promise((resolve, reject) => {     fs.open(filename, mode, (err, fd) => {       if (err) {         reject(err);       } else {         resolve(fd);       }     });   })}  function getFileInfo(fd) {   return new Promise((resolve, reject) => {     fs.fstat(fd, (err, stat) => {       if (err) {         reject(err)       }else {         resolve(stat);       }     });   }) } test();

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

const fs= require('fs'); const http = require('http'); const { copyFile } = require('./build/Release/sendfile.node'); const server = http.createServer(async (req, res) => {   const fd = await openFile('1.txt', 'r');   const { size } = await getFileInfo(fd);   const ret = copyFile(fd, res.socket._handle.fd, size);   res.socket.end(); }).listen(8002);  const {   O_WRONLY,   O_CREAT, } = fs.constants;  function openFile(filename, mode) {   return new Promise((resolve, reject) => {     fs.open(filename, mode, (err, fd) => {       if (err) {         reject(err);       } else {         resolve(fd);       }     });   })}  function getFileInfo(fd) {   return new Promise((resolve, reject) => {     fs.fstat(fd, (err, stat) => {       if (err) {         reject(err)       }else {         resolve(stat);       }     });   })}

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

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

到此,关于“Node.Js中更快的数据传输方式”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注天达云网站,小编会继续努力为大家带来更多实用的文章!

返回web开发教程...