快速写入套接字会导致连接缓冲区

时间:2014-07-19 06:46:51

标签: javascript node.js sockets

我有这段代码来测试服务器,

var client = net.connect({port: 3000}, onConnected);

client.setNoDelay(false);

function onConnected() {
    while (true) {
        client.write('hello');
    }
}

使用debug模块,我看到每个请求的0ms,考虑到它位于同一台机器上。

服务器应该收到<Buffer 68 65 6c 6c 6f>,但服务器实际收到:

<Buffer 68 65 6c 6c 6f 68 65 6c 6c 6f 68 65 6c 6c 6f 68 65 6c 6c 6f 68 65 6c 6c 6f 68 65 6c 6c 6f 68 65 6c 6c 6f 68 65 6c 6c 6f 68 65 6^Cc 6c 6f 68 65 6c 6c 6f 68 ...>

奇怪的行为?实际上不是,如果我理解这一点,就会发生这种情况,因为写入没有立即刷新,导致它在实际发送之前被连接。

但问题是如何解决这个问题并实际接收正确的字节,即使写入套接字非常快。

一个想法是让所有书面数据都以大小为前缀。然后从那个大小读取并从那里切割缓冲区。但问题是我该怎么做?

我认为我不能用这样的东西做到这一点:

socket.on('data', function(data) {
  var len = data[0];

  // hmmmm
})

所以,

  • 有没有办法逐字节读取流并切断每个数据包的第一个字节上指定的每个长度?
  • 更好的选择吗?
  • 还是我错过了这一点?

2 个答案:

答案 0 :(得分:4)

TCP套接字实现流通信,而不是数据包。这意味着您可以写入3个字节,然后写入3个字节,接收器可以在第一次读取时获得5个字节,然后在第二次读取时获得1个字节。

如果你想发送一个数据包,你需要自己对它进行编码,标准方法是首先发送数据包大小,然后发送数据包本身。 E.g。

var szbuf = Buffer(2); // max packet size is 65535
szbuf[0] = msg.size & 255;
szbuf[1] = msg.size >> 8;
write(szbuf); // Send the size
write(msg);   // Send the message

读者首先需要读取2个字节,计算大小然后读取该字节数以获取消息。

如果您需要使用基于消息的通信,可能会使用更高级别的库0MQ,这是一个更好的主意。

如果您只是编写服务器并且协议不包含消息边界(例如类似ascii telnet协议的换行符)那么它很难(不可能)到提供可靠的消息传递,因为TCP不尊重写入和读取边界,因特网上的延迟可以是任意的。

这意味着客户端无法知道消息是否完整。

答案 1 :(得分:0)

@6502答案很棒,但这不是我的用例。

  

警告:我正在分享我写的模块,以帮助我解答我的问题。

所以,我看到这个名为carrier的模块,但它只适用于字符串或新行分隔数据。我需要的是缓冲区,所以基于载体我写了StreamFrame

Boundr 是一个简单的实现,它获取前2个字节上的数据长度并将其剪切到那里,因此 boundr 用于边界< / em>的。我写了一篇关于它的博客文章here

感谢@vaultah评论,这有助于我找到carrier