Node.js net.createServer:大量数据的处理方法

4
我有一个nodejs监听tcp端口并从Flash XMLSocket获取内容。如果我尝试从flash中的一个消息中推送大量数据(XMLSocket.send(long_message)),我总是会在整个消息传输时触发事件stream.on("data", function(d) {,但我希望它在整个消息传输完成后才发生。 Flash的XMLSocket将数据作为以null字节结尾的UTF8编码字符串传输。 如何控制我的消息一致性?
更新
我在这里找到了类似的问题here。但没有明确的答案。我知道我的消息结束应该是null字节,但你能否给我一个存储不完整消息并避免与下一个/并发消息重叠的示例?
更新2
在maerics的回答之后,我做了一些类似的事情。
    var server = net.createServer(function(stream) {
    var dataBlock = "";
    stream.on("data", function(d) {
            processChunk(d);
    });

    function processChunk(data) {
            var chunks = data.split("\0");
            while (chunks.length > 1) {
                    if (dataBlock.length > 0) {
                            dataBlock += chunks.shift();
                            processIncompingMessage(dataBlock);
                            dataBlock = "";
                    }
                    else {
                            processIncompingMessage(chunks.shift());
                    }
            }
            dataBlock += chunks.shift();
    }
    }

你最终的解决方案看起来合理,但是想指出它假定一个消息永远不会超过两个块。 - loganfsmyth
为什么?如果chunks.length的值是5,那么我们将在while循环中循环4次,每次将数组的第一个元素移动,直到chunks.length变为1。之后,如果它等于空字符串 - dataBlock.length下一次将为0,否则它将把部分消息追加到dataBlock中。 - Dmytro Leonenko
是的,昨天我看到的任何问题,现在都没有了,所以我可能只是误读了什么。抱歉 :P 只需记得像下面提到的那样在流上执行 setEncoding。 - loganfsmyth
1个回答

5

以下是我会做的事情(已测试):

var net = require('net');

var server = net.createServer(function (conn) {
  var msg = ''; // Current message, per connection.

  conn.setEncoding('utf8');

  conn.on('message', function (m) {
    console.log('MESSAGE: ' + m);
  });

  conn.on('data', function (data) {
    msg += data.toString('utf8');

    if (msg.charCodeAt(msg.length - 1) == 0) {
      conn.emit('message', msg.substring(0, msg.length - 1));
      msg = '';
    }
  });
});

请注意,单个数据块中可能编码有多个以空值分隔的消息,因此您应该扩展此示例以通过空字符分隔数据并单独处理每个消息。此外,您可能希望在连接“end”事件上处理最终的、潜在不完整的消息。

d包含一个消息的结尾和另一个消息的一部分怎么办?这种情况可能发生吗? - Dmytro Leonenko
@DmytroLeonenko:是的,我刚刚更新了我的答案,提到了这种情况。在这种情况下,您应该扫描数据以查找空值,并为每个封闭文本字符串发出消息。 - maerics
在 while 循环中以某种方式读取数据,查找 null 字节?如果找到-将其附加到先前的部分并处理并启动下一个缓冲区?也许可以使用拆分方法来实现? - Dmytro Leonenko
@DmytroLeonenko 可能最好在流上使用 setEncoding 而不是在每个块上使用 .toString,否则您可能会得到多字节字符的一部分。 - loganfsmyth
@loganfsmyth:说得好。出于好奇,即使我们使用setEncoding(),数据中是否有可能只包含多字节字符的第一个空字节?或者客户端软件(或node.js、操作系统等)保证宽字符不会被截断? - maerics
@maerics 如果你使用setEncoding,那么发出的“data”已经是一个字符串,因此它只会发出有效的字符。你可以在我的答案中阅读更多信息:https://dev59.com/lF_Va4cB1Zd3GeqPW8pa#9046164 - loganfsmyth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接