本文转载自微信公众号「编程杂技」,作者theanarkh。转载本文请联系编程杂技公众号。
创新互联公司专业为企业提供石阡网站建设、石阡做网站、石阡网站设计、石阡网站制作等企业网站建设、网页设计与制作、石阡企业网站模板建站服务,10多年石阡做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。
在Node.js中,当我们给前端返回一个静态文件的时候,我们通常会把文件先读进内容,然后通过socket接口写到底层,从而返回给前端。无论是一次性读取到内存还是使用流式的方式,都不可避免地要把数据从内核复制到用户层,再把数据复制到内核,这是一种低效的方式,因为多了无效的复制。在nginx中,可以通过sendfile指令提供效率。Node.js的copyFile底层使用了sendfile系统调用,但是网络IO的时候,没有使用该API。因为Node.js通过队列的方式,控制数据的写入。那么是否可以实现sendfile的方式来提供这网络IO的效率。首先我们看一下sendfile的好处是什么。
我们看到sendfile通过把内核完成数据的传输,减少了内核和用户层的数据复制,从而提高了效率。下面我们通过napi写一个addon来实现这个功能。
- #include
- #include
- #include
- #include
- #include
- 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的思路,后续有时间继续研究分析。
分享题目:好玩的Sendfile---探索Node.Js中更快的数据传输方式
标题URL:http://www.mswzjz.cn/qtweb/news4/395104.html
攀枝花网站建设、攀枝花网站运维推广公司-贝锐智能,是专注品牌与效果的网络营销公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 贝锐智能