当前位置:首页>python>Tkinter + OPC UA:用Python打通工业物联网的"任督二脉"

Tkinter + OPC UA:用Python打通工业物联网的"任督二脉"

  • 2026-08-18 23:11:37
Tkinter + OPC UA:用Python打通工业物联网的"任督二脉"

工控现场有一种痛,叫做"数据孤岛"。PLC、传感器、SCADA各自为政,数据格式五花八门,想把设备状态实时展示到上位机界面,往往要跨越重重协议壁垒。在我参与的一个产线监控项目里,光是搞清楚Modbus、OPC DA、私有协议之间的转换关系,就折腾了将近两周。

后来切换到 OPC UA(OPC Unified Architecture) 方案之后,整个通信层的复杂度直接降了一个量级。再配合 Python 的 opcua 库和 Tkinter 做可视化界面,从零搭一个能用的工业数据采集客户端,两天内就能跑起来。

读完这篇文章,你将掌握:

  • • OPC UA 的核心概念与节点模型,不再被术语绕晕
  • • 用 python-opcua 库建立连接、读写节点、订阅数据变化的完整流程
  • • 用 Tkinter 构建一个实时刷新的工业监控界面,数据驱动 UI 更新

🔍 问题深度剖析:为什么工业通信这么难搞?

工业现场的通信复杂性,根本上来自于历史遗留的协议碎片化。老旧设备用 Modbus RTU,新设备上 EtherNet/IP,SCADA 系统又只认 OPC DA——每接入一种设备,就要写一套适配代码,维护成本呈指数级上升。

更麻烦的是,传统 OPC DA 基于 Windows DCOM 技术,跨平台几乎无解,防火墙配置也是噩梦级别的。一旦网络拓扑稍微复杂一点,连接就开始抽风。

OPC UA 的出现,就是为了终结这种混乱。 它由 OPC 基金会在2008年推出,核心设计目标是:平台无关、安全可靠、语义丰富。不依赖 DCOM,基于 TCP/IP,天然支持跨平台。更关键的是,它引入了**信息模型(Information Model)**的概念,设备数据不再是裸数据,而是带有类型、层级关系和语义的节点树——这才是它真正的竞争力所在。

在实际项目里,我见过不少开发者的误区:把 OPC UA 当成"另一个 Modbus"来用,只会读写几个寄存器地址,完全没有利用它的订阅机制和节点浏览能力。结果是轮询频率拉满、CPU 占用居高不下,还不如直接用 Modbus 省事。


💡 核心要点提炼:OPC UA 你必须搞懂的三件事

📌 节点模型:一切皆节点

OPC UA 的数据组织方式是一棵地址空间树(Address Space)。每个节点都有唯一的 NodeId,节点类型分为:

  • • Variable 节点:存储实际数据值,比如温度、转速
  • • Object 节点:逻辑容器,类似文件夹
  • • Method 节点:可远程调用的方法

理解这个模型之后,你就会明白为什么 OPC UA 客户端的第一步总是"浏览节点树",而不是直接读地址——因为地址本身就携带了语义。

📌 订阅机制:别再无脑轮询了

OPC UA 提供了Subscription + MonitoredItem 机制。客户端向服务端注册感兴趣的节点,服务端在数据变化时主动推送,而不是客户端每隔100ms去问一次"有没有新数据"。

这个机制在高频数据场景下,CPU 占用可以降低 60%~80%(对比轮询方案,测试环境:i5-12400,100个监控点,采样间隔500ms)。

📌 安全模型:生产环境必须重视

OPC UA 内置了三个安全层:传输加密(TLS)、消息签名、用户认证。开发阶段图省事用 None 安全策略没问题,但上生产前一定要配置证书和用户名密码,否则在工厂内网里也是裸奔状态。


🛠️ 解决方案设计

方案一:建立连接,浏览节点树

先把基础打好。安装依赖:

pip install opcua

下面这段代码实现了连接 OPC UA 服务端、递归浏览节点树的功能。没有真实 PLC 的话,可以用 Prosys OPC UA Simulation Server(免费)做测试。

from opcua import Client
from opcua import ua

defbrowse_nodes(node, indent=0):
"""递归浏览 OPC UA 节点树"""
try:
        node_name = node.get_browse_name()
        node_id = node.nodeid.to_string()
        node_class = node.get_node_class()

        prefix = "  " * indent
print(f"{prefix}[{node_class.name}{node_name.Name} | NodeId: {node_id}")

# 只展开 Object 和 Variable 节点,避免递归过深
if node_class in (ua.NodeClass.Object, ua.NodeClass.Variable):
            children = node.get_children()
for child in children:
                browse_nodes(child, indent + 1)
except Exception as e:
print(f"{'  ' * indent}[Error] {e}")

defmain():
# 替换为你的 OPC UA 服务端地址
    server_url = "opc.tcp://localhost:4840/freeopcua/server/"

    client = Client(server_url)

try:
        client.connect()
print(f"✅ 已连接到服务端: {server_url}")

# 获取根节点,开始浏览
        root = client.get_root_node()
        objects = client.get_objects_node()

print("\n📂 节点树结构:")
        browse_nodes(objects)

except Exception as e:
print(f"❌ 连接失败: {e}")
finally:
        client.disconnect()
print("\n🔌 连接已断开")

if __name__ == "__main__":
    main()

踩坑预警:get_children() 在某些服务端实现里会返回大量系统节点,递归深度容易失控。建议加上深度限制参数,或者只浏览 Objects 节点下的用户数据,别从 Root 开始无限递归。


方案二:订阅数据变化,告别无脑轮询

这是 OPC UA 最值得用的特性。核心思路是:创建订阅对象,把感兴趣的节点注册为 MonitoredItem,服务端数据变化时自动触发回调。

from opcua import Client, ua
import time
import threading

classDataChangeHandler:
"""数据变化回调处理器"""

def__init__(self, callback=None):
self.callback = callback
self.data_cache = {}

defdatachange_notification(self, node, val, data):
"""当订阅节点数据变化时触发"""
        node_id = node.nodeid.to_string()
self.data_cache[node_id] = val

print(f"📡 数据变化 | NodeId: {node_id} | 新值: {val}")

# 如果有外部回调(比如更新 UI),则调用
ifself.callback:
self.callback(node_id, val)

classOpcUaSubscriber:
"""OPC UA 订阅管理器"""

def__init__(self, server_url):
self.server_url = server_url
self.client = Client(server_url)
self.subscription = None
self.handler = None
self._connected = False

defconnect(self, data_callback=None):
"""建立连接并初始化订阅"""
try:
self.client.connect()
self._connected = True
print(f"✅ 连接成功: {self.server_url}")

# 创建数据变化处理器
self.handler = DataChangeHandler(callback=data_callback)

# 创建订阅,发布间隔 500ms
self.subscription = self.client.create_subscription(
                period=500,  # 单位:毫秒
                handler=self.handler
            )
returnTrue
except Exception as e:
print(f"❌ 连接失败: {e}")
returnFalse

defsubscribe_node(self, node_id_str):
"""订阅指定节点"""
ifnotself._connected ornotself.subscription:
print("⚠️ 请先建立连接")
returnNone

try:
            node = self.client.get_node(node_id_str)
            handle = self.subscription.subscribe_data_change(node)
print(f"✅ 已订阅节点: {node_id_str}")
return handle
except Exception as e:
print(f"❌ 订阅失败 [{node_id_str}]: {e}")
returnNone

defread_node_value(self, node_id_str):
"""主动读取节点当前值"""
try:
            node = self.client.get_node(node_id_str)
return node.get_value()
except Exception as e:
print(f"❌ 读取失败 [{node_id_str}]: {e}")
returnNone

defwrite_node_value(self, node_id_str, value):
"""写入节点值(需要服务端允许写入)"""
try:
            node = self.client.get_node(node_id_str)
            node.set_value(value)
print(f"✅ 写入成功 [{node_id_str}] = {value}")
returnTrue
except Exception as e:
print(f"❌ 写入失败 [{node_id_str}]: {e}")
returnFalse

defdisconnect(self):
"""断开连接"""
ifself.subscription:
self.subscription.delete()
ifself._connected:
self.client.disconnect()
self._connected = False
print("🔌 已断开连接")


# 使用示例
if __name__ == "__main__":
    subscriber = OpcUaSubscriber("opc.tcp://localhost:4840/freeopcua/server/")

defon_data_change(node_id, value):
print(f"[UI回调] {node_id} => {value}")

if subscriber.connect(data_callback=on_data_change):
# 订阅 Prosys 模拟服务器的示例节点
# 实际使用时替换为你的节点 ID
        subscriber.subscribe_node("ns=3;i=1001")
        subscriber.subscribe_node("ns=3;i=1002")

try:
print("🔄 监听中,按 Ctrl+C 退出...")
whileTrue:
                time.sleep(1)
except KeyboardInterrupt:
pass
finally:
            subscriber.disconnect()

性能对比数据(测试环境:Windows 11,i5-12400,Python 3.11,100个监控节点):

方案
CPU 占用(均值)
网络流量(均值)
数据延迟
轮询(100ms间隔)
~18%
~2.4 MB/min
<100ms
OPC UA 订阅(500ms发布间隔)
~4%
~0.3 MB/min
<600ms

订阅方案在 CPU 和网络开销上都有显著优势,代价是引入了最多一个发布周期的延迟,对于大多数工业监控场景完全可以接受。


方案三:Tkinter 实时监控界面

有了数据层,现在把它和 UI 结合起来。关键挑战在于线程安全:OPC UA 的回调在后台线程触发,而 Tkinter 的 UI 更新必须在主线程执行。直接在回调里操作 Widget 会导致界面卡死或崩溃。

解决思路是用 queue 做线程间通信,主线程用 after() 定时轮询队列更新 UI。

import tkinter as tk  
from tkinter import ttk, scrolledtext  
import threading  
import queue  
import time  
from opcua import Client, ua  


classOpcUaMonitorApp:  
"""OPC UA 实时监控界面"""

def__init__(self, root):  
self.root = root  
self.root.title("OPC UA 工业数据监控")  
self.root.geometry("800x600")  
self.root.configure(bg="
#1e1e2e")  

# 线程安全队列,用于跨线程传递数据  
self.data_queue = queue.Queue()  

self.client = None
self.subscription = None
self._running = False

# 节点配置:NodeId -> 显示名称  
self.monitored_nodes = {  
"ns=2;s=Channel1.Device1.L1""温度传感器 (°C)",  
"ns=2;s=Channel1.Device1.L2""压力传感器 (kPa)",  
"ns=2;s=Channel1.Device1.F1""电机转速 (RPM)",  
"ns=2;s=Channel1.Device1.I1""液位 (%)",  
        }  

# 存储各节点的 Label 控件引用  
self.value_labels = {}  

self._build_ui()  

# 启动队列消费循环(每100ms检查一次)  
self.root.after(100self._process_queue)  

def_build_ui(self):  
"""构建界面布局"""
# ---- 顶部控制栏 ----        ctrl_frame = tk.Frame(self.root, bg="#313244", pady=8)  
        ctrl_frame.pack(fill=tk.X, padx=10, pady=(100))  

        tk.Label(  
            ctrl_frame, text="服务端地址:",  
            bg="#313244", fg="#cdd6f4", font=("Consolas"10)  
        ).pack(side=tk.LEFT, padx=(105))  

self.url_var = tk.StringVar(value="opc.tcp://127.0.0.1:49320")  
        url_entry = tk.Entry(  
            ctrl_frame, textvariable=self.url_var,  
            width=45, font=("Consolas"10),  
            bg="#45475a", fg="#cdd6f4", insertbackground="#cdd6f4"
        )  
        url_entry.pack(side=tk.LEFT, padx=5)  

self.connect_btn = tk.Button(  
            ctrl_frame, text="连接",  
            command=self._toggle_connection,  
            bg="#89b4fa", fg="#1e1e2e",  
            font=("Microsoft YaHei"10"bold"),  
            relief=tk.FLAT, padx=12, cursor="hand2"
        )  
self.connect_btn.pack(side=tk.LEFT, padx=8)  

# 连接状态指示  
self.status_label = tk.Label(  
            ctrl_frame, text="● 未连接",  
            bg="#313244", fg="#f38ba8",  
            font=("Consolas"10)  
        )  
self.status_label.pack(side=tk.LEFT, padx=5)  

# ---- 数据展示区 ----        data_frame = tk.Frame(self.root, bg="#1e1e2e")  
        data_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)  

# 为每个监控节点创建一张"卡片"  
for i, (node_id, display_name) inenumerate(self.monitored_nodes.items()):  
            card = tk.Frame(data_frame, bg="#313244", relief=tk.FLAT, bd=0)  
            card.grid(row=i // 2, column=i % 2, padx=8, pady=8, sticky="nsew")  

            data_frame.columnconfigure(i % 2, weight=1)  
            data_frame.rowconfigure(i // 2, weight=1)  

# 节点名称  
            tk.Label(  
                card, text=display_name,  
                bg="#313244", fg="#a6adc8",  
                font=("Microsoft YaHei"11)  
            ).pack(pady=(155))  

# 数值显示(大字体,醒目)  
            val_label = tk.Label(  
                card, text="--",  
                bg="#313244", fg="#89dceb",  
                font=("Consolas"28"bold")  
            )  
            val_label.pack(pady=(05))  

# NodeId 小字提示  
            tk.Label(  
                card, text=node_id,  
                bg="#313244", fg="#585b70",  
                font=("Consolas"8)  
            ).pack(pady=(010))  

# 保存引用,后续更新用  
self.value_labels[node_id] = val_label  

# ---- 底部日志区 ----        log_frame = tk.Frame(self.root, bg="#1e1e2e")  
        log_frame.pack(fill=tk.X, padx=10, pady=(010))  

        tk.Label(  
            log_frame, text="运行日志",  
            bg="#1e1e2e", fg="#a6adc8",  
            font=("Microsoft YaHei"10)  
        ).pack(anchor=tk.W)  

self.log_text = scrolledtext.ScrolledText(  
            log_frame, height=6,  
            bg="#181825", fg="#cdd6f4",  
            font=("Consolas"9),  
            state=tk.DISABLED  
        )  
self.log_text.pack(fill=tk.X)  

def_log(self, message):  
"""向日志区写入消息(线程安全,通过队列)"""
        timestamp = time.strftime("%H:%M:%S")  
self.data_queue.put(("log"f"[{timestamp}{message}"))  

def_process_queue(self):  
"""主线程定时消费队列,更新 UI"""try:  
whileTrue:  
                msg_type, payload = self.data_queue.get_nowait()  

if msg_type == "data":  
                    node_id, value = payload  
if node_id inself.value_labels:  
# 格式化数值显示  
ifisinstance(value, float):  
                            display_val = f"{value:.2f}"
else:  
                            display_val = str(value)  
self.value_labels[node_id].config(text=display_val)  

elif msg_type == "log":  
self.log_text.config(state=tk.NORMAL)  
self.log_text.insert(tk.END, payload + "\n")  
self.log_text.see(tk.END)  
self.log_text.config(state=tk.DISABLED)  

elif msg_type == "status":  
                    connected, text = payload  
                    color = "#a6e3a1"if connected else"#f38ba8"
self.status_label.config(text=text, fg=color)  

except queue.Empty:  
pass

# 继续调度,保持循环  
self.root.after(100self._process_queue)  

def_on_data_change(self, node_id, value):  
"""OPC UA 数据变化回调(后台线程调用,只往队列里放数据)"""
self.data_queue.put(("data", (node_id, value)))  
self._log(f"数据更新 {node_id} = {value}")  

def_connect_worker(self):  
"""在后台线程执行连接操作,避免阻塞 UI"""        url = self.url_var.get().strip()  
self._log(f"正在连接: {url}")  

try:  
self.client = Client(url)  

# 简单的用户名密码认证示例(按需开启)  
# self.client.set_user("username")  
# self.client.set_password("password")  
self.client.connect()  
self._log("连接成功,正在初始化订阅...")  

# 创建数据变化处理器(内联实现)  
classHandler:  
def__init__(self, callback):  
self.callback = callback  
# 建立 handle -> node_id 的映射  
self.handle_map = {}  

defdatachange_notification(self, node, val, data):  
                    node_id = node.nodeid.to_string()  
self.callback(node_id, val)  

            handler = Handler(self._on_data_change)  
self.subscription = self.client.create_subscription(500, handler)  

# 订阅所有配置的节点  
for node_id inself.monitored_nodes:  
try:  
                    node = self.client.get_node(node_id)  
self.subscription.subscribe_data_change(node)  
self._log(f"已订阅: {node_id}")  
except Exception as e:  
self._log(f"订阅失败 [{node_id}]: {e}")  

self._running = True
self.data_queue.put(("status", (True"● 已连接")))  
# 更新按钮文字(通过队列不行,直接用 after 在主线程执行)  
self.root.after(0lambdaself.connect_btn.config(text="断开"))  
self._log("监控已启动,等待数据...")  

except Exception as e:  
self._log(f"连接失败: {e}")  
self.data_queue.put(("status", (False"● 连接失败")))  
self.root.after(0lambdaself.connect_btn.config(  
                text="连接", state=tk.NORMAL  
            ))  

def_disconnect(self):  
"""断开连接"""
try:  
ifself.subscription:  
self.subscription.delete()  
self.subscription = None
ifself.client:  
self.client.disconnect()  
self.client = None
except Exception as e:  
self._log(f"断开时异常: {e}")  

self._running = False
self.data_queue.put(("status", (False"● 未连接")))  
self.root.after(0lambdaself.connect_btn.config(text="连接"))  
self._log("已断开连接")  

# 重置所有数值显示  
for label inself.value_labels.values():  
self.root.after(0lambda l=label: l.config(text="--"))  

def_toggle_connection(self):  
"""连接/断开切换"""
ifnotself._running:  
self.connect_btn.config(state=tk.DISABLED)  
# 在后台线程执行连接,不阻塞 UI            t = threading.Thread(target=self._connect_worker, daemon=True)  
            t.start()  
else:  
self._disconnect()  

defon_close(self):  
"""窗口关闭时清理资源"""
self._disconnect()  
self.root.destroy()  


if __name__ == "__main__":  
    root = tk.Tk()  
    app = OpcUaMonitorApp(root)  
    root.protocol("WM_DELETE_WINDOW", app.on_close)  
    root.mainloop()

踩坑预警:

  • • 不要在 OPC UA 回调里直接调用 label.config(),这是最常见的崩溃来源。一定要走队列 + after() 的组合拳。
  • • client.disconnect() 要在后台线程调用时注意异常捕获,某些服务端断线时会抛出 socket 错误,没有 try-except 会导致线程崩溃。
  • • 订阅的 period 参数(发布间隔)不是采样间隔,实际数据推送频率还受服务端采样间隔配置影响,两者要配合调整。

🎯 三句话总结技术洞察

  1. 1. OPC UA 的订阅机制是精髓,用轮询替代订阅是在用21世纪的协议干20世纪的活。
  2. 2. Tkinter 多线程的核心法则:后台线程只负责产数据,主线程只负责渲染,queue 是它们之间唯一合法的通信渠道。
  3. 3. 工业通信的稳定性比性能更重要,异常处理和重连机制的完善程度,决定了系统能不能在产线上真正跑起来。

📚 学习路径与延伸

掌握本文内容之后,下一步可以沿两个方向深入:

协议方向:研究 OPC UA 的信息模型规范(OPC UA Part 5),了解如何为自定义设备建模;进一步可以探索 OPC UA PubSub 模式,适合广播场景。

工程方向:把本文的单机客户端升级为带数据库持久化(SQLite/InfluxDB)的历史数据记录系统,再结合 Matplotlib 或 pyqtgraph 做趋势图,就是一个完整的轻量级 SCADA 雏形了。


💬 欢迎在评论区聊聊你的工业通信经历:你在项目中遇到过哪些奇葩的设备协议?有没有比 OPC UA 更顺手的方案?实战经验的交流往往比文档更有价值。


#Python#OPC UA#工业物联网#Tkinter#上位机开发#工控软件

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-08-21 16:28:20 HTTP/2.0 GET : https://f.mffb.com.cn/a/508336.html
  2. 运行时间 : 0.250887s [ 吞吐率:3.99req/s ] 内存消耗:4,528.80kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=7b08a7cd6af97e54e2dee0d04103dc4f
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.001020s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001412s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000808s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.004910s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001829s ]
  6. SELECT * FROM `set` [ RunTime:0.010022s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001558s ]
  8. SELECT * FROM `article` WHERE `id` = 508336 LIMIT 1 [ RunTime:0.013283s ]
  9. UPDATE `article` SET `lasttime` = 1787300900 WHERE `id` = 508336 [ RunTime:0.020483s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 66 LIMIT 1 [ RunTime:0.003997s ]
  11. SELECT * FROM `article` WHERE `id` < 508336 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.014947s ]
  12. SELECT * FROM `article` WHERE `id` > 508336 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000412s ]
  13. SELECT * FROM `article` WHERE `id` < 508336 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001503s ]
  14. SELECT * FROM `article` WHERE `id` < 508336 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.007625s ]
  15. SELECT * FROM `article` WHERE `id` < 508336 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.000834s ]
0.252452s