Chapter 20_1 table库

本文深入探讨Lua中的table库,涵盖数组操作如插入、删除、排序和连接,以及高级功能如table.pack和table.unpack的使用。通过实例展示了如何利用Lua的table库进行高效的数据管理和操作。

  table库是由一些辅助函数构成,把table作为数组来操作,所有的函数都忽略传入参数的那张表中的非数字键

  无论如何,若一个操作需要取表的长度,这个表必须是一个真序列,或是拥有__len元方法

  提供了这样一些功能:从列表中插入和删除元素、对元素排序、连接一个数组中所有字符串。

  • 插入和删除

  函数table.insert用于将一个元素插入到一个数组指定位置,然后移动后续元素。

  例如数组t = {10,20,30},当调用table.insert(t,1,15)后,t = {15,10,20,30}

  如果insert函数没有指定位置参数,则会自动添加到数组末尾

  下面示例逐行读取输入,并将所有的行保存在一个数组中:

t = {}
for line in io.lines() do
    table.insert(t , line)
end
print(#t)        -->读入的行数

  在Lua5.0的老版本中,这样写很正常,但是在最新的版本中,作者建议这样写:

t[#t+1] = line    --替换insert

 

  函数table.remove会删除(并返回)数组指定位置上的元素,然后后面的元素前移。

  当没有指定位置参数时,会删除最后一个元素

  通过这两个函数可以很方便地实现栈、队列、双向队列。可以用t = {}来初始化这种结构。

  table.insert(t, x )等价于压入操作。

  table.remove(t) 等价于弹出操作。

  table.insert(t , 1 ,x )在结构的另一端插入一个新元素。

  table.remove(t , 1 )会从这一端删除一个元素。

  后两个操作不是很高效,因为必须移动元素。针对较小的数组可以这样使用。

  • 排序

  另一个有用的数组函数table.sort,之前在高阶函数中提到过。它可以对一个数组进行排序,可以指定一个可选的排序函数。

  这个排序函数必须是一个可以接收两个列表内元素为参数的函数,如果希望第一个参数在排序结果中位于第二个参数值前,就应当返回true。

  再次重现之前的例子:

network = {
        {name = "arauna",    IP = "210.26.20.30"},
        {name = "brraial",   IP = "210.26.45.33"},
        {name = "lua",       IP = "210.45.34.56"},
        {name = "derain",    IP = "210.26.23.76"},
}
table.sort(
             network,
             function (a,b)    --这里的a,b参数分别是列表里的两个元素
               return (a.name < b.name) -- "arauna" < "brraial" 为真,所以下面打印是按照name的升序打印
             end
          )
for k,v in pairs(network) do
    print(k,v.name)
end
-->1       arauna
-->2       brraial
-->3       derain
-->4       lua                   

  一个常见的错误是试图对一个table的索引进行排序。在table中,索引是一个无序的集合。

如果对它进行排序,则必须将它们复制到一个数组中,然后再对它进行排序。

下面演示一个示例:假设要读取一个源文件,并构建一个table记录每个函数并定义它的行号,table如下 :

lines = {
    luaH_set = 10,
    luaH_get = 24,
    luaH_present = 48,
}

现在要按照字母次序打印这些函数名。如果用pairs来遍历table,结果是无序的。由于这些名称是table的key,因此不能对她们进行直接排序。

应该先放在一个数组中排序:

a = {}
for n in pairs(lines) do 
    a[#a+1] = n
end
table.sort(a)            --对数组排序,按照默认的小于操作,结果为假,所以打印的是升序排列
for i , n in ipairs(a) do
    print(n)
end    
--> luaH_get
--> luaH_present
--> luaH_set

对于Lua来说,数组也是无序的,它们本质也是table。然而用户知道如何计算索引,因此在访问数组时,只要使用有序的索引,就可以顺序地访问数组。

这就是为什么必须要使用ipairs而不是pairs来遍历数组的原因。因为前者使用1、2、3....的顺序,后者采用table的原始顺序。

  另一个更高级的方法,写一个迭代器,使它根据table key的次序来进行遍历。同时,还有一个可选的参数f,用于指定某种特殊次序:

function parisByKeys(t ,f )
    local a = {}
    for n in pairs(t) do a[#a + 1] = n end
    table.sort(a,f)
    local i = 0          --迭代器变量
    return function()    --迭代器函数
        i = i + 1
        return a[i],t[a[i]] --返回原table中的key和value,即函数名和行号
    end
end

该函数先将key 排序到一个数组中,然后迭代这个数组,每步返回原table中的key和value。

通过这个函数就可以很容易地按照字母次序来打印那些函数名了:

for name , line in pairsByKeys(lines) do
    print(name,line)
end
  • 连接

  之前也用到过table.connect,它接受一个字符串数组,并返回这些字符串连接后的结果。

它有一个可选参数,用于指定插到字符串之间的分隔符。

这个函数另外还接受两个可选参数,用于指定第一个和最后一个要连接的字符串索引。

下面这个函数是table.connect的一个扩展,它能处理嵌套的字符串数组:

function rconcat( t )
    if type(t) ~= "table" then return r end
    local res = {}
    for i = 1 , #t do
        res[i] = rconcat(t[i])  --递归调用自己,以此来连接所有可能嵌套的字符串数组。
    end
    return table.concat(res)
end

最后调用concat来连接这些结果:

print(rconcat{{"a",{" nice"}} , " and",{{" long"}, {" list"}}})
--> a nice and long list
  • 扩展两个有用的函数

  table.pack(...)函数返回一个新表,以1、2、3...为key,参数为值的新表。并将“n”这个域设置为参数的总和。

  这个新表不一定是一个序列。

  table.unpack(list)函数返回列表中的元素,可以加两个参数i ,j 表示要返回的起始索引对应的值。

  等价于:

return list[i],list[i+1]......,list[j]

  所以,如果不设置i 和j ,就表示默认从1到#list

以上内容来自:《Lua程序设计第二版》和《Programming in Lua  third edition 》 和 Lua参考手册

转载于:https://www.cnblogs.com/daiker/p/5890039.html

提交确认的解析结果 @app.route(f"/api/{VERSION}/confirm/parsed", methods=["POST"]) def confirm_parsed_data(): # 获取文档类型 word or excel try: file_type = request.json.get("type") file_name = request.json.get("filename") block_name = request.json.get("block") # 生效范围 effect = request.json.get("effect") # 生效文件范围 file_range = effect.get("file_range", "all") if file_range == "current": # "all" or "current" file_range = os.path.basename(file_name) # 内容范围 content_range = effect.get("content_range", "all") if content_range == "custom": content_range = effect.get("custom_content_range",'') # 表单范围 form_range = effect.get("form_range", "all") if form_range == "current": form_range = block_name if block_name else "all" chapter_range = effect.get("chapter_range", "all") if chapter_range == "current": chapter_range = request.json.get("before", {}).get("chapter", "") if chapter_range in ["", None]: chapter_range = "all" # 数据类型 type_ = request.json.get("before").get("type", "") except AttributeError: return jsonify({ "code": 400, "msg": "确认解析的部分参数缺失." }) logging.info(f"confirm parsed received params: \n file_range: {file_range}; \n content_range: {content_range};" f"\n form_range: {form_range}; \n chapter_range: {chapter_range};") # 处理 用户确认表头 if type_ == "table": head_type = request.json.get("head_type") head_info = request.json.get("head_info") data = { "head_type": head_type, "head_info": head_info } # 新增到形式化规则 write_rule_parse( "table_parse_multi_line_header", "1", "1", "table_parse_multi_line_header", "table", file_range, form_range, chapter_range, content_range, json.dumps([data]) ) logging.info("web server write 'table_parse_multi_line_header' succeed.") # 确认文本的章节号的匹配 if type_ == "text": # 字符串 章节分隔符 value = request.json.get("sep") if value: logging.info("start call 'write_rule_parse', give params:\n" "'text_parse_chapter_match'\n" "'1'\n" "'1'\n" "'text_parse_chapter_match'\n" f"'{file_range}'\n" f"'{form_range}'\n" f"'{chapter_range}'\n" f"'{content_range}'\n" f"'{json.dumps([value])}'") # 新增到形式化规则 write_rule_parse( "text_parse_chapter_match", "1", "1", "text_parse_chapter_match", "text", file_range, form_range, chapter_range, content_range, json.dumps([value]) ) logging.info("web server write 'text_parse_chapter_match' succeed.") return jsonify({ "code": 200, "msg": "确认解析结果成功." }) 一行行解释
09-16
import sys import threading import time import traceback from collections import defaultdict from PyQt5 import QtWidgets, QtCore, QtGui from PyQt5.QtChart import QChart, QChartView, QLineSeries, QPieSeries, QValueAxis from scapy.layers.inet import IP, TCP, UDP, ICMP from scapy.packet import Raw from scapy.layers.l2 import Ether from scapy.sendrecv import sniff from scapy.arch.windows import get_windows_if_list import logging # 配置日志记录器 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler("logs.txt", mode='w', encoding="utf-8"), logging.StreamHandler() ] ) # 全局数据存储 packet_count = 0 packet_list = [] # 存储所有数据包信息 rules = [] # 存储规则信息 # 创建一个锁对象 lock = threading.Lock() # 日志文件路径 LOG_FILE = "logs.txt" CHAPTER_FILE = "chapter.txt" # 清空 chapter.txt 文件 with open(CHAPTER_FILE, "w", encoding="utf-8") as f: f.write("") class PacketAnalyzer(QtWidgets.QMainWindow): update_signal = QtCore.pyqtSignal() # 声明更新信号 error_signal = QtCore.pyqtSignal(str) # 声明错误信号 def __init__(self): super().__init__() self.setWindowTitle("简易防火墙系统") self.setGeometry(100, 100, 1200, 1200) self.initUI() self.update_signal.connect(self.update_packet_table) # 连接信号到槽函数 self.error_signal.connect(self.show_error) # 连接错误信号到槽函数 self.last_packet_id = 0 self.allow_count = 0 self.block_count = 0 self.line_series = QLineSeries() self.pie_series = QPieSeries() self.init_charts() self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.update_charts) self.timer.start(2000) # 每 2 秒更新一次 self.capture_start_time = None # 抓包开始时间 self.last_update_time = 0 # 上次更新时间 self.packet_counts = [] # 存储每2秒的数据包数量 self.time_points = [] # 存储时间点 self.is_capturing = False logging.info("简易防火墙系统初始化完成") def initUI(self): logging.info("开始初始化用户界面") central_widget = QtWidgets.QWidget() self.setCentralWidget(central_widget) layout = QtWidgets.QVBoxLayout(central_widget) top_layout = QtWidgets.QHBoxLayout() self.interface_combo = QtWidgets.QComboBox() # 获取Windows网络适配器列表 self.win_ifaces = get_windows_if_list() for iface in self.win_ifaces: # 使用友好名称作为显示文本,内部名称作为实际值 self.interface_combo.addItem(iface['name'], iface["name"]) top_layout.addWidget(QtWidgets.QLabel("选择网络适配器:")) top_layout.addWidget(self.interface_combo) # 添加规则按钮 self.add_rule_button = QtWidgets.QPushButton("添加规则") self.add_rule_button.clicked.connect(self.add_rule) top_layout.addWidget(self.add_rule_button) # 应用规则按钮 self.apply_rules_button = QtWidgets.QPushButton("应用规则") self.apply_rules_button.clicked.connect(self.apply_rules) top_layout.addWidget(self.apply_rules_button) # 添加开始抓包按钮 self.scan_button = QtWidgets.QPushButton("开始抓包") self.scan_button.clicked.connect(self.start_sniffing) top_layout.addWidget(self.scan_button) # 添加停止抓包按钮 self.stop_button = QtWidgets.QPushButton("停止抓包") self.stop_button.clicked.connect(self.stop_sniffing) self.stop_button.setEnabled(False) # 初始状态禁用 top_layout.addWidget(self.stop_button) # 添加配置方式下拉选项 self.config_mode_combo = QtWidgets.QComboBox() self.config_mode_combo.addItems(["立即更新", "定量更新"]) top_layout.addWidget(QtWidgets.QLabel("配置方式:")) top_layout.addWidget(self.config_mode_combo) layout.addLayout(top_layout) # 规则配置区域 rule_layout = QtWidgets.QHBoxLayout() rule_table_layout = QtWidgets.QVBoxLayout() self.rule_table = QtWidgets.QTableWidget() self.rule_table.setColumnCount(5) self.rule_table.setHorizontalHeaderLabels(["操作", "协议", "源IP", "目的IP", "端口"]) self.rule_table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) self.rule_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) rule_table_layout.addWidget(self.rule_table) # 设置列宽 self.rule_table.setColumnWidth(0, 50) # 操作列 self.rule_table.setColumnWidth(1, 50) # 协议列 self.rule_table.setColumnWidth(2, 150) # 源IP列 self.rule_table.setColumnWidth(3, 150) # 目的IP列 self.rule_table.setColumnWidth(4, 50) # 端口列 # 设置规则区域高度为600 rule_table_widget = QtWidgets.QWidget() rule_table_widget.setLayout(rule_table_layout) rule_table_widget.setFixedHeight(600) rule_layout.addWidget(rule_table_widget) # 图表区域 chart_layout = QtWidgets.QVBoxLayout() self.line_chart_view = QChartView() self.pie_chart_view = QChartView() # 设置每个图表区域高度为300 self.line_chart_view.setFixedHeight(300) self.pie_chart_view.setFixedHeight(300) chart_layout.addWidget(self.line_chart_view) chart_layout.addWidget(self.pie_chart_view) rule_layout.addLayout(chart_layout) layout.addLayout(rule_layout) # 状态栏 self.status_label = QtWidgets.QLabel("就绪") self.statusBar().addWidget(self.status_label) # 数据包列表表格 self.packet_table = QtWidgets.QTableWidget() self.packet_table.setColumnCount(9) self.packet_table.setHorizontalHeaderLabels(["编号", "时间", "协议", "大小", "端口", "源IP", "目标IP", "信息", "操作"]) self.packet_table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) self.packet_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) self.packet_table.cellClicked.connect(self.show_packet_detail) layout.addWidget(self.packet_table) # 隐藏数据包表格的垂直表头 self.packet_table.verticalHeader().setVisible(False) # 调整列宽 self.packet_table.setColumnWidth(0, 50) # 编号 self.packet_table.setColumnWidth(1, 200) # 时间 self.packet_table.setColumnWidth(2, 50) # 协议 self.packet_table.setColumnWidth(3, 50) # 大小 self.packet_table.setColumnWidth(4, 50) # 端口 self.packet_table.setColumnWidth(5, 150) # 源IP self.packet_table.setColumnWidth(6, 150) # 目标IP self.packet_table.setColumnWidth(7, 300) # 信息 self.packet_table.setColumnWidth(8, 50) # 操作 logging.info("UI 初始化完成") def start_sniffing(self): logging.info("开始抓包按钮被点击") # 获取选中的适配器内部名称 current_index = self.interface_combo.currentIndex() iface = self.interface_combo.itemData(current_index) # 创建一个事件用于停止嗅探 self.stop_event = threading.Event() # 启动嗅探线程 self.sniff_thread = threading.Thread(target=self.sniff_packets, args=(iface,)) self.sniff_thread.daemon = True self.sniff_thread.start() # 更新UI状态 self.scan_button.setEnabled(False) self.stop_button.setEnabled(True) self.status_label.setText(f"正在从 {self.interface_combo.currentText()} 捕获数据包...") logging.info(f"开始在适配器 {iface} 上捕获数据包") self.is_capturing = True self.capture_start_time = time.time() # 记录抓包开始时间 self.last_packet_id = 0 # 上次统计时的数据包ID self.last_update_time = 0 # 上次更新时间 self.packet_counts = [] # 存储每2秒的数据包数量 self.time_points = [] # 存储时间点 self.line_series.clear() def stop_sniffing(self): logging.info("点击停止抓包按钮") # 检查嗅探线程是否存在并正在运行 if hasattr(self, 'sniff_thread') and self.sniff_thread.is_alive(): # 设置停止事件 self.stop_event.set() # 更新UI状态 self.status_label.setText("正在停止捕获...") # 等待线程结束 self.sniff_thread.join(timeout=2.0) # 恢复UI状态 self.scan_button.setEnabled(True) self.stop_button.setEnabled(False) self.status_label.setText("捕获已停止") self.is_capturing = False logging.info("数据包捕获已停止") def sniff_packets(self, iface): try: logging.info(f"开始在适配器 {iface} 上捕获数据包...") # 使用stop_filter参数实现优雅停止 sniff(iface=iface, prn=self.process_packet, store=False, stop_filter=lambda x: self.stop_event.is_set()) except OSError as e: error_msg = f"捕获数据包时出错: {e}\n需要管理员权限运行此程序。" logging.error(error_msg) self.error_signal.emit(error_msg) except Exception as e: error_msg = f"错误: {e}\n{traceback.format_exc()}" logging.error(error_msg) self.error_signal.emit(error_msg) finally: # 恢复UI状态 self.scan_button.setEnabled(True) self.stop_button.setEnabled(False) logging.info("数据包捕获停止") def add_rule(self): row_count = self.rule_table.rowCount() self.rule_table.insertRow(row_count) # 操作下拉框 action_combo = QtWidgets.QComboBox() action_combo.addItems(["允许", "阻止"]) self.rule_table.setCellWidget(row_count, 0, action_combo) # 协议下拉框 proto_combo = QtWidgets.QComboBox() proto_combo.addItems(["任意", "TCP", "UDP", "ICMP", "其他"]) self.rule_table.setCellWidget(row_count, 1, proto_combo) # 源IP输入框 src_ip_edit = QtWidgets.QLineEdit() src_ip_edit.setText("任意") self.rule_table.setCellWidget(row_count, 2, src_ip_edit) # 目的IP输入框 dst_ip_edit = QtWidgets.QLineEdit() dst_ip_edit.setText("任意") self.rule_table.setCellWidget(row_count, 3, dst_ip_edit) # 端口输入框 port_edit = QtWidgets.QLineEdit() port_edit.setText("任意") self.rule_table.setCellWidget(row_count, 4, port_edit) def apply_rules(self): global rules rules = [] row_count = self.rule_table.rowCount() for i in range(row_count): action = self.rule_table.cellWidget(i, 0).currentText() proto = self.rule_table.cellWidget(i, 1).currentText() src_ip = self.rule_table.cellWidget(i, 2).text() dst_ip = self.rule_table.cellWidget(i, 3).text() port = self.rule_table.cellWidget(i, 4).text() rule = { "action": action, "proto": proto, "src_ip": src_ip, "dst_ip": dst_ip, "port": port } rules.append(rule) logging.info("规则已应用") def check_rules(self, src, dst, proto, port): # 遍历所有规则 for rule in rules: # 检查协议是否匹配 # 如果规则中的协议是 "任意" 或者与传入的协议相同,则认为协议匹配 proto_match = rule["proto"] == "任意" or rule["proto"] == proto # 检查源 IP 是否匹配 # 如果规则中的源 IP 是 "任意" 或者与传入的源 IP 相同,则认为源 IP 匹配 src_match = rule["src_ip"] == "任意" or rule["src_ip"] == src # 检查目标 IP 是否匹配 # 如果规则中的目标 IP 是 "任意" 或者与传入的目标 IP 相同,则认为目标 IP 匹配 dst_match = rule["dst_ip"] == "任意" or rule["dst_ip"] == dst # 检查端口是否匹配 # 如果规则中的端口是 "任意" 或者与传入的端口相同,则认为端口匹配 port_match = rule["port"] == "任意" or str(rule["port"]) == str(port) # 如果所有条件都匹配 if proto_match and src_match and dst_match and port_match: # 返回规则中定义的操作(允许或阻止) return rule["action"] # 如果没有匹配的规则,默认返回 "允许" return "允许" def process_packet(self, packet): global packet_count, packet_list try: # 提取基本信息 timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(packet.time)) if IP in packet: src = packet[IP].src dst = packet[IP].dst # 确定协议类型 if TCP in packet: proto = "TCP" port = packet[TCP].dport elif UDP in packet: proto = "UDP" port = packet[UDP].dport elif ICMP in packet: proto = "ICMP" port = "无" else: proto = "其他" port = "其他" # 获取数据包大小 size = len(packet) # 构建显示信息 info = f"{proto} {src}:{port} -> {dst}" # 检查规则 action = self.check_rules(src, dst, proto, port) # 构建数据包信息 packet_info = { "id": packet_count, "time": timestamp, "proto": proto, "size": size, "src": src, "port": port, "dst": dst, "info": info, "packet": packet, "action": action } # 提取数据包具体内容 if Raw in packet: payload = packet[Raw].load.hex() # 将负载内容转换为十六进制字符串 else: payload = "无具体内容" # 写入 chapter.txt 文件 with open(CHAPTER_FILE, "a", encoding="utf-8") as f: f.write(f"{packet_count},{action}\n") # 写入日志文件 with open(LOG_FILE, "a", encoding="utf-8") as f: f.write(f"编号: {packet_count}\n") f.write(f"时间: {timestamp}\n") f.write(f"协议: {proto}\n") f.write(f"大小: {size}\n") f.write(f"端口:{port}\n") f.write(f"源IP: {src}\n") f.write(f"目标IP: {dst}\n") f.write(f"操作: {action}\n") f.write(f"内容: {payload}\n") f.write("-" * 80 + "\n") # 增加数据包计数 with lock: packet_count += 1 # 添加到数据包列表 with lock: packet_list.append(packet_info) # 更新UI self.update_signal.emit() logging.debug(f"处理数据包: {info}") except Exception as e: # 捕获数据包处理中的异常,避免程序崩溃 error_msg = f"处理数据包时出错: {e}\n{traceback.format_exc()}" logging.error(error_msg) # 可以选择将错误信息显示在状态栏 self.status_label.setText("处理数据包时出错,继续捕获...") def update_packet_table(self): # 检查窗口是否有效 if not self.isVisible(): return # 限制显示的数据包数量,避免UI卡顿 with lock: display_count = min(1000, len(packet_list)) recent_packets = packet_list[-display_count:] self.packet_table.setRowCount(display_count) for i, packet in enumerate(recent_packets): # 确保编号从1开始 self.packet_table.setItem(i, 0, QtWidgets.QTableWidgetItem(str(i + 1))) self.packet_table.setItem(i, 1, QtWidgets.QTableWidgetItem(packet["time"])) self.packet_table.setItem(i, 2, QtWidgets.QTableWidgetItem(packet["proto"])) self.packet_table.setItem(i, 3, QtWidgets.QTableWidgetItem(str(packet["size"]))) self.packet_table.setItem(i, 4, QtWidgets.QTableWidgetItem(str(packet["port"]))) self.packet_table.setItem(i, 5, QtWidgets.QTableWidgetItem(packet["src"])) self.packet_table.setItem(i, 6, QtWidgets.QTableWidgetItem(packet["dst"])) self.packet_table.setItem(i, 7, QtWidgets.QTableWidgetItem(packet["info"])) self.packet_table.setItem(i, 8, QtWidgets.QTableWidgetItem(packet["action"])) # 自动滚动到底部 if display_count > 0: self.packet_table.scrollToBottom() logging.debug("数据包列表更新完成") def show_packet_detail(self, row, column): with lock: packet_info = packet_list[-min(1000, len(packet_list)) + row] packet = packet_info["packet"] # 构建详细信息 detail = f"数据包 #{packet_info['id']} - {packet_info['time']}\n\n" detail += f"协议: {packet_info['proto']}\n\n" detail += f"大小: {packet_info['size']}\n\n" detail += f"端口: {packet_info['port']}\n\n" detail += f"源: {packet_info['src']} --> 目标: {packet_info['dst']}\n" detail += "数据包内容:\n" detail += packet.show(dump=True) # 显示操作信息 detail += f"\n\n操作: {packet_info['action']}\n" self.detail_text.setText(detail) self.detail_dialog.show() logging.info(f"显示数据包详情: 数据包 #{packet_info['id']}") def show_error(self, error_msg): # 在状态栏显示错误信息 self.status_label.setText("错误") # 弹出错误对话框 QtWidgets.QMessageBox.critical(self, "错误", error_msg) logging.error(f"显示错误信息: {error_msg}") def closeEvent(self, event): # 在窗口关闭时停止嗅探 if hasattr(self, 'stop_event'): self.stop_event.set() # 给线程一些时间来停止 if hasattr(self, 'sniff_thread') and self.sniff_thread.is_alive(): self.sniff_thread.join(timeout=1.0) event.accept() logging.info("窗口关闭") def init_charts(self): # 初始化折线统计图 self.line_chart = QChart() self.line_series = QLineSeries() self.line_series.setName("数据包/2秒") self.line_chart.addSeries(self.line_series) # 设置X轴 self.line_axis_x = QValueAxis() self.line_axis_x.setTitleText("时间 ()") self.line_axis_x.setTickCount(6) # 显示6个刻度 self.line_axis_x.setLabelFormat("%.1f") self.line_chart.addAxis(self.line_axis_x, QtCore.Qt.AlignBottom) self.line_series.attachAxis(self.line_axis_x) # 设置Y轴 self.line_axis_y = QValueAxis() self.line_axis_y.setTitleText("数据包数量") self.line_axis_y.setRange(0, 20) # Y轴固定范围0-20 self.line_axis_y.setTickCount(5) # 0,5,10,15,20共5个刻度 self.line_chart.addAxis(self.line_axis_y, QtCore.Qt.AlignLeft) self.line_series.attachAxis(self.line_axis_y) self.line_chart.setTitle("数据包数量随时间变化") self.line_chart_view.setChart(self.line_chart) self.line_chart_view.setRenderHint(QtGui.QPainter.Antialiasing) # 初始化饼状统计图 pie_chart = QChart() pie_chart.addSeries(self.pie_series) pie_chart.setTitle("允许和阻止的数据包百分比") self.pie_chart_view.setChart(pie_chart) def update_charts(self): if not self.is_capturing or self.capture_start_time is None: return # 未在抓包,不更新图表 current_time = time.time() - self.capture_start_time # 当前抓包持续时间 # 更新折线统计图 with open(CHAPTER_FILE, "r", encoding="utf-8") as f: lines = f.readlines() current_packet_id = len(lines) if lines else 0 # 计算当前时间点对应的2秒区间 current_interval = int(current_time // 2) # 只有当时间超过上一次记录的区间时才更新 if current_interval > self.last_update_time: # 计算该区间内的数据包数量 if self.last_update_time == 0: # 第一个区间 packet_count_in_2s = current_packet_id else: # 后续区间 packet_count_in_2s = current_packet_id - self.last_packet_id self.last_packet_id = current_packet_id self.last_update_time = current_interval # 记录数据 self.packet_counts.append(packet_count_in_2s) self.time_points.append(current_interval * 2) # 更新数据点 self.line_series.clear() for t, count in zip(self.time_points, self.packet_counts): self.line_series.append(t, count) # 更新X轴范围,保持可见区域为最后12秒的数据 visible_range = 12 # 可见范围12秒 if current_time > visible_range: self.line_axis_x.setRange(current_time - visible_range, current_time) else: self.line_axis_x.setRange(0, visible_range) # Y轴范围固定为0-20 self.line_axis_y.setRange(0, 50) # 更新饼状统计图 self.allow_count = 0 self.block_count = 0 with open(CHAPTER_FILE, "r", encoding="utf-8") as f: for line in f: _, action = line.strip().split(",") if action == "允许": self.allow_count += 1 elif action == "阻止": self.block_count += 1 total_count = self.allow_count + self.block_count if total_count > 0: allow_percentage = round(self.allow_count / total_count * 100, 2) block_percentage = round(self.block_count / total_count * 100, 2) else: allow_percentage = 0 block_percentage = 0 self.pie_series.clear() self.pie_series.append(f"允许 ({allow_percentage}%)", allow_percentage) self.pie_series.append(f"阻止 ({block_percentage}%)", block_percentage) if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) window = PacketAnalyzer() window.show() logging.info("应用程序启动") sys.exit(app.exec_())使用pydivert修改代码,使其保留原有功能,并且可以在实际网络测试中实现拦截数据包进入或传出防火墙
06-08
# 确认差分的数据 @app.route(f"/api/{VERSION}/confirm/diff", methods=["POST"]) def confirm_diff_data(): try: request_data = request.json diff_block = request.json.get("diff_data").get("block_name") file_type = "excel" if diff_block else "word" old_path = request.json.get("old_path") new_path = request.json.get("new_path") old_filename = os.path.dirname(old_path) new_filename = os.path.dirname(new_path) old_block_name = request.json.get("old_block") new_block_name = request.json.get("new_block") old_chapter = request.json.get("old_chapter", "") new_chapter = request.json.get("new_chapter", "") # 生效范围 effect = request.json.get("effect") # 生效文件范围 file_range = effect.get("file_range", "all") if file_range == "current": file_range = old_filename + "&&" + new_filename else: file_range = file_range + "&&" + file_range # 内容范围 content_range = effect.get("content_range", "all") if content_range == "custom": content_range = effect.get("custom_content_range") content_range = content_range + "&&" + content_range else: content_range = content_range + "&&" + content_range form_range = effect.get("form_range", "all") if form_range == "current": form_range = old_block_name + "&&" + new_block_name else: form_range = form_range + "&&" + form_range # word章节范围 chapter_range = effect.get("chapter_range", "all") if chapter_range == "current" and (old_chapter or new_chapter): chapter_range = old_chapter + "&&" + new_chapter else: chapter_range = "all" + "&&" + "all" except AttributeError: return jsonify({ "code": 400, "msg": "确认差分缺少部分参数" }) logging.info(f"confirm diff received params: \n file_range: {file_range}; \n content_range: {content_range};" f"\n form_range: {form_range}; \n chapter_range: {chapter_range};") # 新增到形式化规则 if request_data.get('update_type') in ['表格序号', "テーブル順序", "Table Order"]: write_rule_parse( "table_seq", "0", # 差分 "1", "table_compare_seq", "table", file_range, form_range, chapter_range, content_range, json.dumps([]) ) elif request_data.get('update_type') in ['文本顺序', "テキスト順序", "Text Order"]: write_rule_parse( "text_seq", "0", "1", "text_compare_seq", "text", file_range, form_range, chapter_range, content_range, json.dumps([]) ) return jsonify({ "code": 200, "msg": "提交确认差分结果OK." })
09-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值