尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
基于Python的时间胶囊区块链:AES-GCM加密、链上存证与时间锁实践
简介“区块链上的时间胶囊”项目源码与学习素材适合具备 Python 编程基础、希望进一步接触区块链时间戳与智能合约开发的读者可用于理解信息上链、加密保存及到期解锁等场景的基本实现思路并体会分布式系统中透明性与隐私保护的权衡。压缩包共24个文件约159KB主要由9个JavaScript脚本、6个Vue组件、2个Solidity合约及JSON配置、HTML入口等组成分别对应合约部署、前端交互、路由配置与项目初始化等环节。目前已有203人学习。借助合约、迁移脚本和Vue界面读者可以梳理时间胶囊从创建、部署到交互的完整结构理解链上时间戳、数据加密与智能合约解锁条件如何配合。项目把不可篡改的链上记录与前端操作分开组织读者还能参考其目录划分和模块职责搭建自己的区块链小项目。1. 时间胶囊不是玄学拆开就是加密、存证、时间锁三件事有人问我把一段话封进 Python 写的区块链设个未来时间点不到那个时间点谁都打不开——这事靠谱吗我第一反应是别把它想成什么神秘装置。它其实是三件普通工程事叠在一起先用对称加密把内容封成密文再把密文摘要和元数据写进链上交易拿到不可篡改的存证最后用一个时间锁规则卡住解密入口。这个项目就是把这套流程做成可跑的单机节点加命令行工具适合想入门链式数据结构、又不想啃庞大框架的 Python 开发者也适合要做一个给未来自己留话小工具的人。它不追求公链级别的吞吐追求的是链路完整、每一步都能看懂、改得动。2. 工程骨架一条链、一个胶囊、一套 CLI 怎么分层拿到源码先别急着pip install先看目录。这类小项目的坑往往不在算法而在分层没分清楚——加密逻辑写进区块类节点接口直接操作文件最后想换个存储后端就得全篇改。这套代码按数据结构 / 密码学 / 网络 / 交互四层切开每层只依赖下一层改起来心里有底。2.1 目录结构与各层职责timecapsule-chain/ ├── capsule/ │ ├── __init__.py │ ├── block.py # 区块头、哈希计算、Merkle 根 │ ├── transaction.py # 胶囊交易结构与 txid │ ├── blockchain.py # 链管理、校验、难度调整 │ ├── crypto.py # AES-GCM 封装/解封、密钥派生、签名 │ ├── timelock.py # 时间锁策略逻辑锁/顺序锁/阈值锁 │ ├── wallet.py # 密钥对生成与本地保存 │ ├── mempool.py # 待打包交易池 │ ├── storage.py # JSON 快照 SQLite 索引 │ └── node.py # Flask HTTP 接口 ├── cli.py # 命令行入口 ├── config.py # 全局参数 ├── tests/ # pytest 用例 └── requirements.txtblock.py只认哈希不碰密码学细节crypto.py只认字节不知道区块长什么样node.py只做参数校验和转发业务全在blockchain.py。这种切法看着啰嗦但后面想加 P2P 或者换 SQLite改动面能控制在单个文件内。我一般把config.py放在最外层而不是包内原因是它经常要跟着部署环境变放包里容易被误提交。配置项也不多出块目标时间、初始难度、难度调整窗口、链数据路径、节点端口五个够用。2.2 依赖选型Flask 加 cryptography 的组合依赖清单很短这是好事# requirements.txt Flask3.0.3 # 节点 HTTP 接口轻量够用 requests2.32.3 # 节点间同步 cryptography42.0.8 # AES-GCM、椭圆曲线签名 pytest8.2.2 # 测试为什么不上 FastAPI做过就知道这类工具项目大部分时间是命令行在跑HTTP 接口只是附属FastAPI 带进来的 pydantic 版本约束反而会在老环境上翻车。Flask 三个装饰器就能把接口写完调试时curl一把梭。密码学库选cryptography而不是自己拼pycryptodome关键在 AES-GCM 的 AAD附加认证数据支持更顺手。时间胶囊这个场景我强烈建议把解锁时间塞进 AAD——密文和元数据绑死谁改了交易里的unlock_at字段解密直接报认证失败。这一点后面第 4 章会展开。签名部分用cryptography的 Ed25519密钥短、签名快、没有曲线参数选择困难症。钱包私钥落盘前用scrypt派生一层口令密钥再加密虽然本地工具谈不上多高安全等级但至少别让私钥以明文躺在磁盘上。2.3 配置项与启动参数# config.py import os BASE_DIR os.path.dirname(os.path.abspath(__file__)) CHAIN_FILE os.path.join(BASE_DIR, data, chain.json) INDEX_DB os.path.join(BASE_DIR, data, index.db) TARGET_BLOCK_TIME 30 # 目标出块间隔单位秒 INITIAL_DIFFICULTY 4 # 前导零个数 ADJUST_INTERVAL 10 # 每 10 个块调整一次难度 MAX_TX_PER_BLOCK 50 # 单块交易上限 NODE_PORT 5000INITIAL_DIFFICULTY 4意味着哈希前面要有 4 个十六进制 0笔记本上大概几百毫秒到两秒能出一个块适合演示。调到 6 就会明显变慢调到 7 基本可以泡杯茶了——这不是夸张是血泪经验第一次跑千万别直接上 6。TARGET_BLOCK_TIME和ADJUST_INTERVAL是配套的难度调整公式在blockchain.py里实际耗时比目标快就加难度慢就减单次调整幅度限制在一倍以内避免震荡。这个设计抄的是主流链的常见做法小项目照抄不吃亏。2.4 从零把节点拉起来环境准备和第一条命令python -m venv .venv source .venv/bin/activate pip install -r requirements.txt # 初始化链数据目录和创世块 python cli.py init --difficulty 4 # 另开终端启动 HTTP 节点 python cli.py serve --port 5000init做的事很简单建data/目录、生成创世块、写一份空的chain.json。创世块的previous_hash固定为 64 个 0timestamp用当前时间取整到秒这样重跑初始化得到的创世块哈希可复现方便测试断言。serve起来后curl http://127.0.0.1:5000/chain应该能拿到一个只含创世块的 JSON。拿不到先别怀疑代码八成是端口被占或者虚拟环境没激活——这两种情况我各踩过一次。3. 核心模块拆解一个区块从交易打包到落盘的完整链路这一章是整套代码的主干。链路是胶囊交易进内存池 → 打包成区块 → 算 Merkle 根 → 挖矿找 nonce → 落盘 → 广播。每一环都有个容易被忽略的细节写错一处后面校验就过不去。3.1 交易结构与 Merkle 根胶囊交易不是普通转账字段要多一些# transaction.py import hashlib import json import time import uuid def build_capsule_tx(ciphertext: bytes, unlock_at: int, recipient_pub: str, meta: dict) - dict: 构造一条胶囊交易链上只存密文与元数据 tx { txid: , # 稍后由内容哈希填充 type: capsule, created_at: int(time.time()), unlock_at: int(unlock_at), # Unix 秒解锁时间点 recipient: recipient_pub, # 收件人公钥hex cipher: ciphertext.hex(), # AES-GCM 密文含 tag meta: meta, # 算法、nonce、salt、文件名等 nonce: uuid.uuid4().hex, # 防同内容重复导致 txid 冲突 } tx[txid] tx_hash(tx) return tx def tx_hash(tx: dict) - str: 规范化序列化后取 SHA-256保证跨机器一致 payload {k: v for k, v in tx.items() if k ! txid} raw json.dumps(payload, sort_keysTrue, separators(,, :)) return hashlib.sha256(raw.encode()).hexdigest()sort_keysTrue加separators去空格这两步不能省。JSON 默认序列化会带空格键顺序也依赖插入顺序两个节点对同一条交易算出的 txid 就可能不一样同步时直接对不上。这个坑不显眼但排查起来很费时间因为单机跑永远正常。Merkle 根的决定性作用是让区块头能代表整块交易# block.py def merkle_root(tx_hashes: list[str]) - str: if not tx_hashes: return hashlib.sha256(b).hexdigest() layer list(tx_hashes) while len(layer) 1: if len(layer) % 2 1: # 奇数个就复制最后一个 layer.append(layer[-1]) layer [ hashlib.sha256((layer[i] layer[i 1]).encode()).hexdigest() for i in range(0, len(layer), 2) ] return layer[0]参数是交易哈希列表返回单个 64 位十六进制串。奇数层复制末尾这个处理是标准做法不复制的话两两配对会漏一个不同实现对同一批交易算出不同根跨节点校验必然失败。空块返回空串的哈希而不是空字符串是为了让compute_hash的拼接逻辑统一。3.2 区块哈希与 PoW 挖矿区块头字段的顺序一旦定下就不能改改了历史块的哈希全部作废# block.py import hashlib import json class Block: def __init__(self, index, timestamp, transactions, previous_hash, difficulty, nonce0): self.index index self.timestamp int(timestamp) # 一律用整型秒 self.transactions transactions self.previous_hash previous_hash self.difficulty difficulty self.nonce nonce self.merkle_root merkle_root([t[txid] for t in transactions]) def header(self) - dict: return { index: self.index, timestamp: self.timestamp, merkle_root: self.merkle_root, previous_hash: self.previous_hash, difficulty: self.difficulty, nonce: self.nonce, } def compute_hash(self) - str: raw json.dumps(self.header(), sort_keysTrue, separators(,, :)) return hashlib.sha256(raw.encode()).hexdigest() def mine(self, difficulty: int) - str: target 0 * difficulty while not self.compute_hash().startswith(target): self.nonce 1 return self.compute_hash()timestamp强制int()类型转换是刻意的。浮点秒在不同平台序列化出来可能是1717000000.0也可能是1717000000JSON 一序列化哈希就变了重启后整条链校验不过——这就是所谓的玄学问题其实是类型不统一。挖矿循环里每次compute_hash都重新做一次json.dumps难度 4 的时候感觉不出来难度上去了就是性能瓶颈。真要提速把 header 前缀序列化一次缓存起来nonce 单独拼。不过演示项目保持可读性优先我倾向不优化让读代码的人一眼看懂在干嘛。3.3 链接管verify_chain 的五道校验Blockchain类管着链的增删查核心是校验函数# blockchain.py class Blockchain: def __init__(self, difficulty4, adjust_interval10, target_time30): self.chain: list[Block] [] self.difficulty difficulty self.adjust_interval adjust_interval self.target_time target_time self.mempool [] def verify_chain(self) - tuple[bool, str]: for i in range(1, len(self.chain)): cur, prev self.chain[i], self.chain[i - 1] if cur.previous_hash ! prev.compute_hash(): return False, f块 {i} 前哈希不匹配 if not cur.compute_hash().startswith(0 * cur.difficulty): return False, f块 {i} 工作量不足 if cur.merkle_root ! merkle_root( [t[txid] for t in cur.transactions]): return False, f块 {i} Merkle 根被篡改 if cur.timestamp prev.timestamp: return False, f块 {i} 时间戳未单调递增 for tx in cur.transactions: if tx[txid] ! tx_hash(tx): return False, f块 {i} 交易 {tx[txid]} 被改动 return True, ok五道校验对应五个攻击面改前块、改难度、改交易集合、倒填时间戳、改单笔交易内容。任何一项不过链就整条拒绝不给部分信任的余地。注意cur.timestamp prev.timestamp用的是非严格单调同一个秒内出两个块在生产链上会碰壁本地测试又经常一秒出一个。我的处理是出块时强制max(now, prev.timestamp 1)让时间戳自动往后推一秒校验逻辑保持严格。这属于工程折中不是理论最优但能让测试跑顺。3.4 持久化JSON 快照加 SQLite 索引链数据用 JSON 整存整取简单直接# storage.py import json import os def save_chain(path: str, blocks: list[dict]) - None: os.makedirs(os.path.dirname(path), exist_okTrue) tmp path .tmp with open(tmp, w, encodingutf-8) as f: json.dump({blocks: blocks}, f, ensure_asciiFalse, sort_keysTrue, indent2) os.replace(tmp, path) # 原子替换防写一半断电 def load_chain(path: str) - list[dict]: if not os.path.exists(path): return [] with open(path, encodingutf-8) as f: return json.load(f).get(blocks, [])os.replace这步是后悔药。直接open(path, w)写到一半进程被杀chain.json就成了半截文件下次启动解析失败整条链看起来凭空消失。先写临时文件再原子替换至少保证要么是旧版本要么是新版本。SQLite 只做索引不存全量区块txid、block_index、unlock_at、recipient四个字段建表按解锁时间倒排查询时能秒回。全量数据还是 JSON理由是调试时用编辑器直接打开看最省事索引库删了也能从 JSON 重建。4. 时间锁与加密封装胶囊怎么封、怎么到期才开封胶囊和解胶囊是两套不对称的逻辑。封装时只需要收件人公钥和解锁时间解密时除了私钥还得确认链上时间已经过了点。这一章把交易字段、AES-GCM 封装、三种时间锁策略和解锁流程讲透。4.1 链上只放密文胶囊交易字段设计字段设计有一条铁律明文永远不上链。链上存的东西任何人可见一旦写入就撤不回来。字段类型是否上链说明txidstring是内容哈希交易唯一标识unlock_atint是Unix 秒参与 AAD 绑定recipientstring是收件人 Ed25519 公钥 hexcipherstring是AES-GCM 密文加认证标签 hexmeta.algstring是固定AESGCM-256meta.noncestring是12 字节 GCM noncemeta.saltstring是scrypt 盐16 字节meta.filenamestring是原文文件名可选plaintextbytes否只在本地内存出现meta.filename这种字段泄露的信息很少但如果你要封的是敏感内容连文件名都该塞进密文里meta只留算法参数。这个取舍看你自己的场景代码里留了开关。4.2 AES-GCM 封装与 scrypt 密钥派生# crypto.py import os from cryptography.hazmat.primitives.ciphers.aead import AESGCM from cryptography.hazmat.primitives.kdf.scrypt import Scrypt def derive_key(password: bytes, salt: bytes) - bytes: kdf Scrypt(saltsalt, length32, n2 ** 14, r8, p1) return kdf.derive(password) def seal(plaintext: bytes, password: bytes, unlock_at: int) - dict: salt os.urandom(16) nonce os.urandom(12) # GCM nonce绝不复用 key derive_key(password, salt) aes AESGCM(key) aad funlock_at{unlock_at}.encode() # 绑死解锁时间 ct aes.encrypt(nonce, plaintext, aad) return { cipher: ct.hex(), meta: { alg: AESGCM-256, nonce: nonce.hex(), salt: salt.hex(), }, }n2**14的 scrypt 参数在笔记本上大概 50 到 100 毫秒安全性和体验的平衡点。想更硬可以上2**17代价是每次解封多等半秒。aad传进去的那行是整个时间锁防篡改的关键。交易里的unlock_at如果被人从 2030 年改成 2025 年解密时 AAD 对不上AESGCM.decrypt直接抛InvalidTag。这就是把元数据变成密码学承诺比在业务层写if now unlock_at靠谱得多。nonce 复用是 GCM 模式的致命伤同一个 key 加同一个 nonce 加密两段不同明文密钥流可被还原。代码里每次os.urandom(12)现生成不做任何缓存。4.3 时间锁的三种实现层次时间锁在密码学上有不同段位项目里三种都留了接口第一种逻辑锁。最常用也最容易被误解。节点和解封客户端都检查now unlock_at不到点直接拒。它的约束力来自社会共识——节点软件守规矩你就打不开。缺点也很明显改本地系统时间或者自己拿私钥私下去解没人拦得住。# timelock.py import hashlib def vdf_key(seed: bytes, rounds: int) - bytes: 顺序锁连续哈希 rounds 次只能串行算 h seed for _ in range(rounds): h hashlib.sha256(h).digest() return h第二种顺序锁。上面这段是极简的时间锁谜题密钥要连续迭代哈希 N 次才能得到N 越大耗时越长。想提前拿到密钥唯一办法就是老老实实算完 N 次算力换时间。它不是严格意义上的 VDF真正的 VDF 还需要证明可快速验证但在这个项目里用来说明解密成本随时间增长够了。要调难度就改rounds十万次大概几百毫秒百万次就上秒级了。第三种阈值锁。把密钥拆成 m 份交给 n 个持有者凑够 t 份才能还原。项目里用一个简单的 Shamir 分片演示适合做多个见证人共同见证的场景。实现比前两种复杂代码放在timelock.py后半段默认不启用。提示逻辑锁、顺序锁、阈值锁可以叠加。先用顺序锁抬高提前解密的成本再用阈值锁分散信任最后用逻辑锁卡住客户端入口三层叠起来才算有点样子。4.4 解锁流程拿链上中位时间说话解胶囊的入口函数# crypto.py from cryptography.hazmat.primitives.ciphers.aead import AESGCM def open_capsule(tx: dict, password: bytes, chain_median_time: int) - bytes: unlock_at tx[unlock_at] if chain_median_time unlock_at: raise PermissionError( f未到解锁时间还差 {unlock_at - chain_median_time} 秒) meta tx[meta] salt bytes.fromhex(meta[salt]) nonce bytes.fromhex(meta[nonce]) key derive_key(password, salt) aes AESGCM(key) aad funlock_at{unlock_at}.encode() return aes.decrypt(nonce, bytes.fromhex(tx[cipher]), aad)第二个参数chain_median_time是重点它不是本地time.time()。取值逻辑是取最近 11 个区块时间戳的中位数def median_time_past(blocks: list[Block], window: int 11) - int: recent [b.timestamp for b in blocks[-window:]] recent.sort() return recent[len(recent) // 2]用中位数而不是最新块时间戳是为了防止有人用刚出的一个时间戳异常的块当借口提前开锁。11 个块的中位数至少要影响 6 个块才能推动成本比改本地时钟高得多。这个思路在主流的链上都有影子属于成熟做法。抛PermissionError而不是返回None是为了让 CLI 层能区分还没到点和密码错了——前者提示剩余时间后者直接报认证失败用户体验差别很大。5. 常见问题排查跑不通、解不开、链分叉的现场记录这一章都是我自己和身边人真实踩过的坑按现象、原因、解决三段写。遇到问题先对号入座比盲改代码快得多。5.1 挖矿卡死不动CPU 跑满却不出块现象执行python cli.py mine终端没输出等了五分钟还在转CPU 单核 100%。原因多半是difficulty设太高。前导零每多一个期望尝试次数翻 16 倍难度 4 大概几千次哈希难度 6 就到百万级纯 Python 每轮还要做一次 JSON 序列化速度上不去。另一种可能是compute_hash每次重新序列化区块头nonce 递增却没复用前缀白白多算。解决办法先把config.py里的INITIAL_DIFFICULTY改回 4 验证流程跑通了再往上试。想真提速把 header 里不变的部分预先序列化成字符串循环内只拼 noncedef mine_fast(block: Block, difficulty: int) - str: prefix json.dumps( {k: v for k, v in block.header().items() if k ! nonce}, sort_keysTrue, separators(,, :))[:-1] # 去掉右花括号 target 0 * difficulty while True: raw f{prefix},nonce:{block.nonce}}} h hashlib.sha256(raw.encode()).hexdigest() if h.startswith(target): return h block.nonce 1这个改法把耗时降一个量级但代码可读性会下降建议只在演示前临时用。5.2 重启后链校验失败提示前哈希不匹配现象昨天能跑的链今天python cli.py verify报块 3 前哈希不匹配但代码一个字没改。原因几乎都是序列化不一致。检查两处timestamp是不是被某处写成了浮点json.dump时有没有加sort_keysTrue。Python 的json.dumps在字典键顺序不同的时候输出不同字符串创世块如果是先用默认顺序写入后来又用sort_keys读取重算哈希必然对不上。解决办法所有涉及哈希计算的序列化统一走一个函数参数固定sort_keysTrue, separators(,, :)不要各处手写。已经写坏的链数据用python cli.py repair --rebuild-index从 JSON 重建索引并重算哈希前提是区块内容本身没被改只修序列化差异。5.3 解密报 InvalidTag密码明明是对的现象open_capsule抛cryptography.exceptions.InvalidTag输了三遍密码都一样。原因有三类。第一AAD 不一致。封装时unlock_at是整型解密时如果从 JSON 读回来变成字符串funlock_at{unlock_at}拼出来的字节数组不同认证直接失败。第二nonce 或 salt 的十六进制串大小写、空格不对导致bytes.fromhex解出不同字节。第三封装和解封用了不同的 scrypt 参数派生出的密钥自然不同。解决办法封和解两端共用同一个build_aad()函数参数先int()强制类型meta字段 hex 统一小写、去空格scrypt 的n/r/p写进meta里存着而不是从配置读。def build_aad(unlock_at) - bytes: return funlock_at{int(unlock_at)}.encode()5.4 多节点同步后分叉两边都认为自己是对的现象两个节点跑了一段时间各自/chain返回的最新区块不同重启任何一个都自愈不了。原因是选链规则用了长度比较而不是累计工作量比较。难度调低之后短链可能比长链难挖得多单看长度会选错。另一个隐性原因是同步时没校验对端区块的工作量直接接收了低难度块。解决办法把resolve逻辑改成比累计难度def chain_work(blocks: list[Block]) - int: return sum(16 ** b.difficulty for b in blocks)接收对端链之前先跑一遍verify_chain并要求chain_work(remote) chain_work(local)两个条件都满足才替换。16 ** difficulty是期望尝试次数的近似够用不必引入精确的难度目标值计算。5.5 时间胶囊被提前打开的三个漏洞现象设了三年后解锁结果第二天就解开了。第一个漏洞明文密码或密钥被写进交易meta备注里。虽然看着像调试用一旦上链永久可见。第二个漏洞客户端只比对本地time.time()系统时间一改立刻放行。第三个漏洞节点没校验unlock_at的合理性允许写入一个过去的时间戳。对应三条修法meta白名单校验只允许alg/nonce/salt/filename四个键其他一律拒收解锁时间统一取median_time_past不信任本地时钟提交交易时空节点检查unlock_at median_time_past() 60防止写入刚过期的时间。注意这三条只堵住软层面的漏洞。真要防有算力的人得靠顺序锁抬成本或者干脆把密钥交给第三方托管链上只放解锁凭证。安全边界想清楚再动手别指望一个开关解决所有问题。6. 二次开发把单机玩具改成能用的三处切入点代码跑通之后想往下走我建议按改造收益从高到低排。第一处存储换成 IPFS 或者对象存储链上只放 CIDcipher字段改成cidmeta里加size和sha256做完整性校验。这样区块体积能压到几百字节同步速度差别肉眼可见。第二处共识从 PoW 换成轻量的 PoA 或轮值出块。演示项目里挖矿纯粹为了秀链路实际部署时本地节点挖矿只会白白烧电。做法是保留Block.mine接口把difficulty固定为 0加一个validator_set白名单出块权按轮次分配verify_chain里多一道签名校验。第三处把顺序锁换成真正的 VDF 或者接入可信时间源做双重校验。这一步投入大但能把可信时间从社交共识升级成密码学保证。我一般先在timelock.py里加一个可插拔策略接口class TimeLockStrategy: def compute_key(self, seed: bytes) - bytes: ... def verify(self, seed: bytes, key: bytes) - bool: ...然后写IterHashLock、ShamirLock、RemoteTSALock三个实现配置里切换。接口一立后面不管加什么策略都不用动业务代码。验证方法也简单每次改完跑一遍pytest tests/ -k seal or verify再手动python cli.py verify一次最后起两个节点同步一轮看/chain是否一致。三关都过才算改对。最后说个教训。早些年我做一个类似的存证小工具图省事把序列化逻辑散在四个文件里各写各的json.dumps上线三个月后加个字段整条链的哈希全变了历史数据一条都验不过只能写脚本逐块重算。从那以后我每次动靠近哈希计算的代码都强制先跑一遍全链校验再提交。这类项目看着小但哈希和序列化这种地基一旦松动修起来比从头写还费劲。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

LogManager启动后在忙什么:三类后台线程撑起日志全生命周期

LogManager启动后在忙什么:三类后台线程撑起日志全生命周期

摘要:上一篇讲了 LogManager 是什么、Broker 启动时如何加载恢复日志。这篇接着追问:日志恢复完、Broker 对外服务之后,LogManager 还在做什么?答案藏在 startup() 方法里——它会拉起三类后台线程:一个单线程调度器、…

📅 2026/10/30 11:12:16
你的第一个开源 PR 指南:Null Motion 本地开发环境、good first issue 清单与 PR 规范

你的第一个开源 PR 指南:Null Motion 本地开发环境、good first issue 清单与 PR 规范

【免费下载链接】NullMotion Play a finished motion-graphics ad in sync with the rough drafts it grew from, and export the breakdown as MP4. 项目地址: https://gitcode.com/gh_mirrors/nu/NullMotion 点击查看 免费下载 Null Motion 是一个本地运行的动效…

📅 2026/10/30 11:12:16
iDRAC9 240天试用License:解锁R740/R440远程KVM与虚拟介质

iDRAC9 240天试用License:解锁R740/R440远程KVM与虚拟介质

简介:iDRAC9 Enterprise 240天试用版许可证面向戴尔R740、R440等第14代服务器的系统管理员、IT运维人员,用于快速解锁服务器远程管理控制台的完整企业级功能。这份资源体积极小,压缩包仅2KB,内部包含1个XML格式的许可证文件&#…

📅 2026/10/30 11:12:16
MORE NEWS

更多资讯

📰

效率工具软件选型与自动化指南:从工具收集到流程自动化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

用户脚本自动填问卷:DOM事件模拟与受控组件赋值实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

全栈自造Status Deck:ESP32-S3与BLE技术栈选型实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

嵌入式I2C外设调试全攻略:从硬件波形到软件驱动的系统化排查方法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

导弹飞控为何禁用malloc:硬实时系统内存确定性设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Qt QWidget自研滚动选择器:无QML实现iOS风格Picker

简介:这是一份基于Qt框架实现的滚动数字选择器(类似手机闹钟时间设置控件)源码资源,面向Qt初学者与GUI开发进阶者,解决移动端风格交互控件在桌面/嵌入式场景下的复现难题。资源包共31个文件,含7个C源文件&a…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬