如何通过response.write在node.js中正确发送缓冲区?

时间:2019-07-16 01:16:36

标签: node.js node.js-buffer

我正在尝试从node.js服务器发送二进制内容。为此,我分配了一个缓冲区,并用我的内容填充了缓冲区,然后在其上调用response.write()。返回后,我将缓冲区与新内容一起重用。但是,由于某些原因,它似乎无法正常工作。

这是服务器代码:

const http = require('http');

async function sendChunk( response, outbuf )
{
    console.log( "Sending buffer: %s", outbuf );

    // Send the buffer out. If it returns false, 
    // this means the kernel buffers are full,
    // and we have to wait until they are available.
    if ( await response.write( outbuf ) === false )
    {
        await new Promise(resolve => response.once('drain', ()=>{
            resolve();
        }));
    }
}

async function sendData( response )
{
    let outbuf = Buffer.alloc( 20 );

    for ( let count = 0x45; count < 0x50; count++ )
    {
        for ( let i = 0; i < outbuf.length; i++ )
        {
            outbuf[i] = count;
        }

        await sendChunk( response, outbuf );
    }
}


function webRequestHandler( request, response )
{
    let body = [];

    request.on('error', (err) => {
        console.error(err);
        return;

    });

    request.on('data', (chunk) => {
        body.push(chunk);
    });

    response.on('error', (err) => {
        console.error( "Error sending response: %s", err);
        return;
    });

    // A whole body collected - process it
    request.on('end', async () => {

        // Handle the update; can return an error message
        response.setHeader('Content-Type', 'text/plain');
        await sendData( response );
        response.end();
    });
}

const webserver = http.createServer( webRequestHandler );

// Create the web service
webserver.on('error', function (err) {
    console.log("[" + process.pid + "] " + JSON.stringify(err));
    process.exit();
});

webserver.listen( { "host" : "127.0.0.1", "port" : 5252 }, () => {
    console.log( "Server running" );
});

通过curl http://localhost:5252/测试时,服务器将打印以下内容:

Sending buffer: EEEEEEEEEEEEEEEEEEEE
Sending buffer: FFFFFFFFFFFFFFFFFFFF
Sending buffer: GGGGGGGGGGGGGGGGGGGG
Sending buffer: HHHHHHHHHHHHHHHHHHHH
Sending buffer: IIIIIIIIIIIIIIIIIIII
Sending buffer: JJJJJJJJJJJJJJJJJJJJ
Sending buffer: KKKKKKKKKKKKKKKKKKKK
Sending buffer: LLLLLLLLLLLLLLLLLLLL
Sending buffer: MMMMMMMMMMMMMMMMMMMM
Sending buffer: NNNNNNNNNNNNNNNNNNNN
Sending buffer: OOOOOOOOOOOOOOOOOOOO

但是客户收到的东西完全不同:

> curl http://localhost:5252/
EEEEEEEEEEEEEEEEEEEEOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO

这是怎么回事?如果在sendChunk中创建一个新缓冲区(这是outbuf的副本),它将起作用。但是,这似乎浪费了RAM,对于来自C背景的人来说并没有什么意义,一旦在套接字上调用send(),就已经复制了数据,并且可以在使用时重新使用源缓冲区希望。

node.js的工作方式不同吗?我是否需要为response.write()创建一个专用缓冲区,即使写返回并且我等待了drain事件,调用写操作后也无法再触摸它吗?

1 个答案:

答案 0 :(得分:0)

我发布了the bug report,并以一条重要的评论告终:

  

您应该将回调传递给.write()才能知道节点何时处于   完成那块内存,而不是依靠“流失”   事件。

     

进行更改后,您将在客户端上看到以下输出:   您正在期待。

实际上,sendChunk函数的更改如下:

async function sendChunk( response, outbuf )
{
    return new Promise( function( resolve, reject) {

        if ( response.write( outbuf, ()=>{ resolve(); } ) === false )
        {
            console.log( "Draining buffer" );
            response.once('drain', ()=>{
                resolve();
            });
        }
    });
}

所以我们只在函数回调中解决它,问题就消失了。这里的核心问题是response.write不可等待,并且在调用回调之前返回。

应该更仔细地阅读文档。