本文转载自微信公众号「编程杂技」,作者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中更快的数据传输方式
                
                文章地址:http://www.csdahua.cn/qtweb/news4/395104.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网