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

如何解析tshark实时输出的JSON流?

解析tshark JSON输出流的最佳实践

你提到之前是逐行解析tshark的常规文本输出,现在切换到-T json的JSON数组格式(且只看到首个数据包),想要高效的流解析方案——毕竟如果是实时抓包或者处理大量数据包,把整个JSON数组加载到内存显然不现实。下面是几个实用的方案,按易用性排序:

方案1:让tshark输出换行分隔的JSON(最省心)

其实tshark从3.0版本开始支持-T ndjson格式,它会把每个数据包单独输出为一行JSON,完全避开了数组包裹的问题,直接就能逐行解析,和你之前处理常规输出的逻辑几乎一致!

使用命令:

tshark -i <接口> -T ndjson

然后在Python中处理的示例:

import subprocess
import json

# 启动tshark进程,获取输出流
proc = subprocess.Popen(
    ["tshark", "-i", "eth0", "-T", "ndjson"],
    stdout=subprocess.PIPE,
    text=True
)

# 逐行解析每个数据包的JSON
for line in proc.stdout:
    if line.strip():  # 跳过空行
        packet = json.loads(line)
        # 处理数据包,比如打印源IP
        print(packet.get("ip.src", "N/A"))

这个方案不需要额外依赖,逻辑简单,适合大多数场景。如果你的tshark版本低于3.0,也可以用-l选项强制刷新输出,配合-T json加上-j指定要输出的字段(避免输出整个数组结构),不过ndjson是更标准的选择。

方案2:用流解析库处理JSON数组

如果必须使用-T json的数组格式,那么可以用支持增量解析的JSON库,比如ijson或者json-stream,它们都能处理类文件对象(比如subprocess的stdout),不需要把整个数组加载到内存。

以ijson为例,先安装库:

pip install ijson

然后解析tshark的JSON输出流:

import subprocess
import ijson

proc = subprocess.Popen(
    ["tshark", "-i", "eth0", "-T", "json"],
    stdout=subprocess.PIPE,
    binary=True  # ijson需要二进制流
)

# 解析数组中的每个元素(每个数据包)
for packet in ijson.items(proc.stdout, "item"):
    # 处理数据包
    print(f"数据包长度: {packet.get('frame.len', 'N/A')}")

ijson会逐个提取数组里的item元素,也就是每个数据包的JSON对象,完美适配你的需求。你提到的NAYA库也是类似原理,同样可以用这种方式传入类文件对象(proc.stdout本身就是类文件对象)来解析。

方案3:手动用内置json模块实现流解析

如果不想依赖第三方库,也可以用Python内置的json.JSONDecoder的raw_decode方法手动处理流:

import subprocess
import json

proc = subprocess.Popen(
    ["tshark", "-i", "eth0", "-T", "json"],
    stdout=subprocess.PIPE,
    text=True
)

decoder = json.JSONDecoder()
buffer = ""
for chunk in iter(lambda: proc.stdout.read(1024), ""):
    buffer += chunk
    while True:
        try:
            # 尝试解析buffer中的JSON
            obj, idx = decoder.raw_decode(buffer)
            # 如果是数组开头,跳过
            if isinstance(obj, list):
                buffer = buffer[idx:]
                continue
            # 处理单个数据包对象
            print(f"源端口: {obj.get('tcp.srcport', 'N/A')}")
            buffer = buffer[idx:]
        except ValueError:
            # 没有足够的字符完成解析,继续读下一块
            break

这个方法需要自己处理缓冲区和数组的起始标记,代码稍微繁琐,但好处是不需要安装额外依赖,适合环境受限的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:22:56