You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js通过TCP传输解析大JSON文件失败问题求助

TCP传输大JSON解析失败:解决流数据分段问题

看起来你遇到的核心问题是TCP是面向流的协议,而非面向消息——简单来说,当你发送大JSON时,数据会被拆分成多个数据包分段传输。你的代码现在在data事件触发时就直接尝试解析,但此时拿到的可能只是完整JSON的一部分,自然会抛出语法错误。本地环境因为传输距离极短,数据大概率一次性到达,所以不会触发这个问题,但线上服务器的网络传输必然会出现分段情况。

你的代码问题分析

看错误日志里的"Cha明显是"Channel_Name"的开头片段,这说明这次data事件只收到了JSON的一部分。你当前的代码每次触发data事件时,直接用pack = JSON.parse(d)解析当前片段,完全忽略了TCP流的特性,这是导致报错的直接原因。

解决方案:先拼接完整数据再解析

你需要先把所有收到的数据拼接起来,直到确认完整的JSON已经接收完毕,再进行解析。这里有两种实用的实现方式:

方案1:用换行符作为消息结束标记

在发送JSON时,在末尾追加一个换行符\n作为消息结束的约定标记。服务器端每次收到数据后先拼接,再检查是否包含结束标记,确认完整后再解析:

var express = require('express'); 
var net = require("net"); 
var app = express(); 
var server = net.createServer(); 

// 允许跨域
app.use(function(req, res, next){ 
  res.header("Access-Control-Allow-Origin", "*"); 
  next(); 
}); 

// 用参数化路由替代动态添加路由,避免路由冲突
app.get('/data/:formatNumber', function(req, res){ 
  const storedData = req.app.get(`data_${req.params.formatNumber}`);
  if (storedData) {
    res.setHeader('Content-Type', 'application/json');
    res.send(storedData);
  } else {
    res.status(404).send('Data not found');
  }
});

server.on("connection", function(socket){ 
  let receivedData = ""; // 每个连接单独维护接收的数据
  socket.setEncoding('utf8'); 

  socket.on("data", function(d){ 
    receivedData += d; // 追加数据,而非覆盖
    // 检查是否收到结束标记(发送方需在JSON末尾加\n)
    if (receivedData.includes('\n')) {
      // 分割出所有完整消息,过滤空行
      const completeMessages = receivedData.split('\n').filter(msg => msg.trim());
      for (const msg of completeMessages) {
        try {
          const parsedData = JSON.parse(msg); 
          console.log(`Received data for FormatNumber: ${parsedData.FormatNumber}`);
          // 用唯一键存储数据,避免冲突
          app.set(`data_${parsedData.FormatNumber}`, msg); 
        } catch (err) {
          console.error('JSON解析错误:', err);
        }
      }
      receivedData = ""; // 重置,准备接收下一条消息
    }
  }); 

  socket.once("close", function(){ 
    console.log("connection closed"); 
  }); 
}); 

server.on("error", function(err){ 
  console.log("connection error:", err); 
}); 

server.listen(9000, function(){ 
  console.log("TCP Server Listening to Port 9000"); 
}); 

app.listen(8081, function(){ 
  console.log("Express Server Listening to Port 8081");
}); 

方案2:先发送数据长度,再发送JSON(更可靠的大文件方式)

这种方式适合超大文件传输,步骤如下:

  1. 发送方先计算JSON的字节长度,把长度转换成固定格式(比如8位数字字符串)发送;
  2. 服务器先接收长度,再根据长度接收对应字节数的JSON数据,直到全部接收完成再解析。

服务器端核心修改示例:

server.on("connection", function(socket){ 
  let state = 'waiting-for-length'; // 当前状态:等待接收长度
  let expectedLength = 0;
  let receivedData = "";

  socket.on("data", function(d){ 
    if (state === 'waiting-for-length') {
      // 假设长度是8位固定长度字符串,比如"00012345"
      receivedData += d;
      if (receivedData.length >= 8) {
        const lengthStr = receivedData.slice(0,8);
        expectedLength = parseInt(lengthStr, 10);
        receivedData = receivedData.slice(8);
        state = 'waiting-for-data';
      }
    }

    if (state === 'waiting-for-data') {
      receivedData += d;
      // 检查是否已接收足够长度的数据
      if (Buffer.byteLength(receivedData, 'utf8') >= expectedLength) {
        const completeJson = receivedData.slice(0, expectedLength);
        try {
          const parsedData = JSON.parse(completeJson);
          console.log(`Received data for FormatNumber: ${parsedData.FormatNumber}`);
          app.set(`data_${parsedData.FormatNumber}`, completeJson);
        } catch (err) {
          console.error('JSON解析错误:', err);
        }
        // 处理剩余的多余数据(如果存在多条消息)
        const remaining = receivedData.slice(expectedLength);
        receivedData = remaining;
        state = 'waiting-for-length';
      }
    }
  }); 
});

额外注意事项

  1. 你原代码里尝试访问pack.Timestamp.LocalTimestamp,但示例JSON中并没有Timestamp字段,这会导致额外报错,请检查数据结构;
  2. 动态添加路由的方式会导致路由冲突,建议用参数化路由(如/data/:formatNumber)替代;
  3. 响应的Content-Type应该设置为application/json,方便客户端直接解析。

内容的提问来源于stack exchange,提问作者Jason Chen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:46:47