这篇文章主要介绍“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给前端返回对应的内容,最后关闭连接。结果如下。
关于“Node.Js中怎么实现更快的数据传输”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网行业资讯频道,小编每天都会为大家更新不同的知识点。