Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Json 在Node.js中从TCP套接字读取字符串时出现问题_Json_Node.js_Sockets - Fatal编程技术网

Json 在Node.js中从TCP套接字读取字符串时出现问题

Json 在Node.js中从TCP套接字读取字符串时出现问题,json,node.js,sockets,Json,Node.js,Sockets,我已经实现了一个使用TCP套接字进行通信的客户机/服务器。我正在向套接字写入的数据是字符串化的JSON。最初一切都按预期进行,但是,随着写入速率的增加,最终会遇到JSON解析错误,客户机上的开始在旧写入的结尾接收新写入的开始 以下是服务器代码: var data = {}; data.type = 'req'; data.id = 1; data.size = 2; var string = JSON.stringify(data); client.write(string, callback(

我已经实现了一个使用TCP套接字进行通信的客户机/服务器。我正在向套接字写入的数据是字符串化的JSON。最初一切都按预期进行,但是,随着写入速率的增加,最终会遇到JSON解析错误,客户机上的开始在旧写入的结尾接收新写入的开始

以下是服务器代码:

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(';'));
然而,这种方法并没有导致JSON解析错误,反而会导致客户端完全丢失一些请求,因为我将每秒的写入速率提高了300以上

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


谢谢

尝试使用
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.
});

希望对您有所帮助。

您使用分隔符的方法是正确的。但是,您不能只提取分隔符之前的内容,处理它,然后丢弃它之后的内容。您必须缓冲在分隔符之后得到的任何内容,然后连接它旁边的内容。这意味着您可以在给定的
数据
事件之后得到任意数量(包括0)的JSON“块”


基本上,您保留一个缓冲区,您可以将其初始化为
”。在每个
数据
事件中,您将接收到的任何内容连接到缓冲区的末尾,然后
拆分
在分隔符上添加缓冲区。结果将是一个或多个条目,但最后一个条目可能不完整,因此需要测试缓冲区,以确保它以分隔符结尾。如果不是,则弹出最后一个结果并将缓冲区设置为该结果。然后处理剩下的任何结果(可能不是任何结果)。

请注意,TCP不会保证将接收到的数据块划分在何处。它所能保证的是,除非连接完全失败,否则您发送的所有字节都将按顺序接收

我相信只要套接字告诉您它有数据,Node
data
事件就会出现。从技术上讲,您可以为JSON数据中的每个字节获取单独的
数据
事件,并且它仍然在操作系统允许的范围内。没有人会这样做,但您的代码需要编写得好像它可能会在任何时候突然开始发生一样,以保持健壮。由您来组合数据事件,然后沿着对您有意义的边界重新分割数据流

为此,您需要缓冲任何未“完成”的数据,包括附加到“完成”数据块末尾的数据。如果使用的是分隔符,千万不要在分隔符之后丢弃任何数据——始终将其作为前缀保留,直到看到更多数据,最终看到另一个分隔符或结束事件

另一种常见的选择是在所有数据前面加上长度字段。假设您使用固定的64位二进制值。然后您总是等待8个字节,再加上这些字节中的值所指示的更多字节到达。假设有一大块10字节的数据传入。您可能在一个事件中得到2个字节,然后是5个字节,然后是4个字节——此时您可以解析长度并知道还需要7个字节,因为第三个块的最后3个字节是有效负载。如果下一个事件实际上包含25个字节,那么您将从前面的7个字节和3个字节中提取并解析它,然后在字节8-16中查找另一个长度字段


这是一个人为的例子,但请注意,在低流量下,网络层通常会以您提供的任何数据块发送您的数据,因此这类事情只会在您增加负载时才真正开始出现。一旦操作系统开始一次从多个写操作生成数据包,它将开始以对网络方便而不是对您方便的粒度进行拆分,您必须对此进行处理。

感谢大家的解释,他们帮助我更好地理解通过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
    }      
});

欢迎评论…

以下回复:

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
    }      
});
我对分隔符有问题,因为
是我发送的数据的一部分

可以使用此更新来实现自定义分隔符:

var chunk = "";
const DELIMITER = (';;;');
client.on('data', function(data) {
    chunk += data.toString(); // Add string on the end of the variable 'chunk'
    d_index = chunk.indexOf(DELIMITER); // 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+DELIMITER.length); // Cuts off the processed chunk
        d_index = chunk.indexOf(DELIMITER); // Find the new delimiter
    }      
});

有两个相关的问题,]。在这两种方法中,解决方案都是使用分隔符,再加上存储上一条消息的剩余内容。不幸的是,似乎还没有更好的解决方案。这不适用于socket communicationclient中的NodeJ。在('end',函数(){})上,当套接字与服务器断开连接时,将触发该函数。如果使用套接字连接传输多条消息,并且我们需要在不断开服务器连接的情况下读取单个消息,该怎么办?