从Node.js中的TCP套接字读取string时出现问题

我已经实现了使用TCP套接字进行通信的客户机/服务器。 我写入套接字的数据是string化的JSON。 最初一切正常,但是,随着写入速度的提高,我最终遇到了JSONparsing错误,其中客户端的开始部分在旧部分的末尾接收到新写入的开始。

这里是服务器代码:

var data = {}; data.type = 'req'; data.id = 1; data.size = 2; var string = JSON.stringify(data); client.write(string, callback()); 

以下是我在客户端服务器上接收此代码的方式:

 client.on('data', function(req) { var data = req.toString(); try { json = JSON.parse(data); } catch (err) { console.log("JSON parse error:" + err); } }); 

我收到的错误率是:

 SyntaxError: Unexpected token { 

这似乎是下一个请求被标记到当前结尾的开始。

我试过使用; 作为每个JSON请求结束处的分隔符,然后使用:

  var data = req.toString().substring(0,req.toString().indexOf(';')); 

但是,这种方法,而不是导致JSONparsing错误似乎导致完全丢失客户端的一些请求,因为我提高了写入速度超过300每秒。

是否有任何最佳实践或更有效的方法来通过TCP套接字分隔传入的请求?

谢谢!

感谢大家的解释,他们帮助我更好地理解数据通过TCP套接字发送和接收的方式。 以下是我最后使用的代码的简要概述:

 var chunk = ""; client.on('data', function(data) { chunk += data.toString(); // Add string on the end of the variable 'chunk' d_index = chunk.indexOf(';'); // Find the delimiter // While loop to keep going until no delimiter can be found while (d_index > -1) { try { string = chunk.substring(0,d_index); // Create string up until the delimiter json = JSON.parse(string); // Parse the current string process(json); // Function that does something with the current chunk of valid json. } chunk = chunk.substring(d_index+1); // Cuts off the processed chunk d_index = chunk.indexOf(';'); // Find the new delimiter } }); 

欢迎评论…

你使用分隔符正确的轨道。 但是,你不能在分隔符之前提取东西,处理它,然后丢弃它后面的东西。 你必须缓冲分隔符之后的任何内容,然后连接它旁边的内容。 这意味着在一个给定的data事件之后,最终可能会包含任何数量(包括0个)的JSON“块”。

基本上你保留一个缓冲区,你初始化为"" 。 在每个data事件上,你将你接收到的任何内容连接到缓冲区的末尾,然后split分隔符split成缓冲区。 结果将是一个或多个条目,但最后一个可能不完整,所以您需要testing缓冲区以确保以分隔符结束。 如果没有,你popup最后的结果,并设置你的缓冲区。 你然后处理任何结果(可能不是)。

请注意,TCP不会保证它将接收到的数据块分成几个部分。 所有它保证的是,你发送的所有字节将按顺序接收,除非连接完全失败。

我相信只要套接字说有数据给你,节点data事件就会进来。 从技术上讲,您可以为JSON数据中的每个字节分别获取data事件,并且仍然在OS允许的范围内。 没有人会这样做,但是你的代码需要被写入,就好像它可以在任何时候突然开始发生一样。 您需要合并数据事件,然后将数据stream重新分割为对您有意义的边界。

要做到这一点,你需要缓冲任何不完整的数据,包括附加在“完整”数据块尾部的数据。 如果您使用分隔符,请勿在分隔符后面丢弃任何数据 – 始终将其作为前缀保留,直到您看到更多数据并最终显示另一个分隔符或结束事件。

另一个常见的select是用长度字段前缀所有数据。 假设你使用一个固定的64位二进制值。 然后你总是等待8个字节,再加上这些字节中的数值表明,到达。 假设你有十个字节的数据传入。 你可能会在一个事件中得到2个字节,然后是5个,然后是4个 – 在这一点上,你可以parsing长度,知道你需要7个字节,因为第三个块的最后3个字节是有效载荷。 如果下一个事件实际上包含了25个字节,那么你会从前面的3个中取出前7个,并parsing它,然后查找字节8-16中的另一个长度字段。

这是一个人为的例子,但是请注意,在低stream量的情况下,networking层通常会以您提供的任何数据块的forms发送数据,所以这种情况只有在您增加负载时才会显现出来。 一旦操作系统开始同时从多个写入开始构build数据包,它将开始分割,这对于networking而言不是很方便,而且您必须处理这个问题。

尝试end事件,没有数据

 var data = ''; client.on('data', function (chunk) { data += chunk.toString(); }); client.on('end', function () { data = JSON.parse(data); // use try catch, because if a man send you other for fun, you're server can crash. }); 

希望能帮到你。