news 2026/10/1 7:05:32

以太网温湿度采集的断线重连与断点续传机制解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
以太网温湿度采集的断线重连与断点续传机制解析

先讲一件真事。前年我负责一个药品阴凉库的温湿度监控改造,采集器用的是带以太网口的嵌入式设备,上报频率30秒一次。上线当天一切正常,结果第二天凌晨三点被值班电话吵醒——库房温湿度曲线从零点开始出现一整段空洞。排查到最后,原因是库房配电柜旁边的一根网线被叉车压断,设备断线后又没有重连和数据补传逻辑,网络恢复后只能干瞪眼,监控大屏上永远是“离线”。

这个项目之后我彻底想明白一件事:以太网温湿度采集通讯,难点从来不在“读取传感器”和“把数据塞进TCP包”,而在网络链路不可靠时,如何保证数据不丢、链路自愈、历史可补。本文要聊的是一套实际落地在温湿度采集器上的通讯机制设计,涵盖多协议支持(Modbus TCP、MQTT、HTTP)、断线重连状态机、断点续传缓存与确认机制,以及现场踩过的那些文档里不会写的坑。适合正在做环境监控采集器、IoT网关、工业数据上云的嵌入式或后端工程师参考。

1. 温湿度采集通讯的需求拆解:为什么“低频数据”反而最怕断线

1.1 数据的“低频高价值”特性决定了通讯设计方向

温湿度数据和视频流、高频振动数据完全不同,它的采集频率通常很低,短则1秒一条,长则5分钟一条。单条数据本身只有几十字节,一年满打满算也就几百万条,算下来占用的带宽和存储几乎可以忽略不计。

但恰恰是这种低频数据,对“连续性”的要求高得吓人。

一个医药冷库的温度标准可能是2℃到8℃,一旦温度越界,监管要求你必须能证明“从什么时候开始越界、持续了多久”。如果中间断了一小时数据,审计人员根本不会认可“这段时间大概率没问题”这种解释。数据缺失=记录缺失=管理事故。所以温湿度采集通讯系统的第一设计原则从来不是“把单条数据发出去”,而是“保证端到端的数据最终连续、完整、可追溯”。

这一点和常见的文件传输有本质区别:文件传丢了可以重新传整个文件,但温湿度数据如果断了几小时,重新生成这几小时的“假数据”根本不可能。唯一的办法是在源头把它缓存下来,等待链路恢复后补传。

1.2 一条完整链路中,哪些环节最容易断

一个典型的以太网温湿度采集系统,设备端到服务器之间隔着好几层:

  • 采集器自身的以太网PHY和协议栈
  • 现场的交换机或路由器
  • 跨网段时的防火墙和NAT设备
  • 服务器端的监听服务进程

每一层都可能出问题。我在多个现场踩到过这几类典型的断链:

  • 交换机和设备之间自协商失败,网口指示灯亮着,物理层显示link up,但设备收不到任何ARP响应
  • 路由器NAT会话超时,默认空闲超时一般是300秒。设备保持TCP连接不发数据,连接被静默拆除,设备端还以为自己在线
  • 服务器端服务重启或部署更新,旧连接没有正常发FIN包,设备端半开连接,直到自己发数据收到RST才反应过来
  • 供电不稳导致采集器反复重启,尤其是现场用POE供电但交换机POE预算不足的情况

这些断链场景有一个共同特点:它不是你关掉设备电源那种明确的“下线”,而是链路状态和设备本地状态不一致。处理这种“半开连接”和“静默失效”,正是断线重连机制要解决的问题。

1.3 “重连”和“续传”必须配套设计,缺一个都白搭

我最初接手这个项目时,只想着加一个断线重连。后来发现,只加重连根本没用。

链路恢复后,设备确实能重新连上服务器,但它只会把“当前这一条”数据发上去。断线期间积累的数据全部留在本地,如果不做续传,历史空洞照样存在。反过来,如果只做续传不做重连,那缓存里的数据永远没有机会传出去。

所以这两者是一对闭环设计:断线重连负责“把通道重新建立起来”,断点续传负责“把通道断开期间欠下的数据补上去”。没有续传,重连只是表面在线;没有重连,续传连触发的机会都没有。

这套设计还有一个隐含要求:断线期间设备必须持续在本地采集并缓存数据,而不是停下来等待。设备的本职是“采集”,通讯只是“运输”。运输断了,采集不能断。

2. 多协议选型:Modbus TCP、MQTT、HTTP不是排他关系

2.1 为什么一个采集器要支持多协议

有的工程师会问:直接定一种协议不就行了,为什么要做多协议?

答案在两个场景里很清楚。

第一个场景是存量设备集成。很多现场的PLC或者老式环境监控主机只支持Modbus TCP,你新上的温湿度采集器如果不同时支持这个协议,就只能另配协议转换网关,成本和故障点都增加。第二个场景是服务器端不固定。同一个采集器可能今天接的是客户自己的SCADA系统,明天被接到云端IoT平台,两边的协议栈完全不一样。与其给每个项目都定制固件,不如在设备端做一个可配置的协议层。

这里要强调一个原则:多协议指的是“同一份数据,按配置选择通道和格式”,而不是每个协议维护一套独立的数据逻辑。协议只是编码和传输方式,数据的来源、缓存、补传逻辑必须统一。

2.2 Modbus TCP:兼容存量工业设备的最稳选项

Modbus TCP在工业场景里的地位不用多说,结构简单,报文是纯粹的寄存器读写。温湿度传感器挂到Modbus TCP上通常就是把温度和湿度映射到两个保持寄存器,比如温度寄存器地址0x0001,湿度0x0002,单位精确到0.1。

从通讯机制设计来看,Modbus TCP有几个特点需要注意:

  • 它是一种“请求-响应”协议,服务器轮询设备。设备端不能主动推数据,只能等PLC或上位机来读
  • 默认端口502,报文有MBAP头+功能码+数据,CRC在TCP模式下是不需要的
  • 它没有应用层心跳机制,连接断开只能靠TCP本身去判断

这带来一个设计上的麻烦:如果采集器作为Modbus TCP的Server,断线重连逻辑几乎没法做,因为主动发起连接的是对方。所以在多协议架构里,Modbus TCP更适合作为“被动服务”存在:PLC周期性来读寄存器,我们保证寄存器的值永远是最新的,同时把每次被读走的记录标记为已同步。真正需要主动上报和断点续传的业务,走MQTT或HTTP通道。

2.3 MQTT:给云端平台准备的默认通道

MQTT是这批温湿度采集器里我最推荐的上报协议,主要原因有三个:

一是始终保持长连接但极其轻量。一条温湿度数据转成JSON后可能才100字节不到,加上MQTT的固定头开销也就几个字节,非常适合小带宽场景。

二是QoS等级可以匹配不同的可靠性要求。QoS 0最多一次,QoS 1至少一次,QoS 2恰好一次。对温湿度数据来说,用QoS 1很合适:允许重复,但绝不能丢,重复由服务器端去重即可。

三是天然适合多个订阅方。同一个温湿度主题,既可以给监控平台订阅,也可以给告警服务订阅,互不影响。

不过MQTT有一个需要特别注意的点:它自带的心跳机制是PINGREQ/PINGRESP,间隔由KeepAlive参数控制,默认可以设到60秒甚至更长。但实际网络里,NAT会话超时、交换机老化时间都可能比这个值短。我的建议是:在公网或跨NAT场景下,KeepAlive不要超过30秒;如果用的是4G或者WiFi这类不稳定链路,甚至可以缩到15秒。代价只是每15秒多几个字节的PING包,完全值得。

2.4 HTTP作为兜底通道:简单但别当主力

HTTP上报的好处是接入成本极低,服务器端随便写个接口就能收。缺点是开销相对较大,而且HTTP是典型的请求-响应模型,设备要主动POST,服务器没法主动下发控制指令,至少得用轮询配合。

在这个项目里,我把HTTP设计成“兜底通道”,触发条件有两个:

  1. MQTT连续多次连接失败,确认当前网络到MQTT broker不通
  2. 设备检测到服务器端HTTP接口可达,但MQTT端口被运营商或防火墙屏蔽

这种场景在真实项目里遇到不止一次。某些客户的网络安全策略非常严格,只放行了80/443端口,其他端口一律不通。这时候MQTT走不了,但HTTP还能用,数据就不至于完全断供。

HTTP断点续传的实现也比较直白:设备把缓存数据分批POST到服务器的补传接口,每批附带起始序列号和结束序列号,服务器返回ACK。这里要特别注意HTTP连接的复用,如果一个一个POST,每次都要重新建TCP连接,效率太低;最好是同一个连接内连续上传多批数据,传完一批再请求下一批。

2.5 协议层之上的统一数据抽象

多协议共存最怕的是各写各的,最后逻辑乱成一团。我在设计时把所有协议收敛到同一个统一数据模型上:

  • 设备ID:全局唯一,出厂写入
  • 序列号:单调递增,本地持久化,是断点续传的游标基础
  • 采集时间:设备本地时间戳,单位秒
  • 温度值、湿度值:浮点
  • 采集质量标记:正常/越界/传感器异常

不管是走MQTT、HTTP还是Modbus寄存器的值,底层都从这个统一模型取出。缓存和续传也只针对这个模型操作,和具体协议无关。这样后期再加一个CoAP或者WebSocket,完全不需要动缓存层的代码。

3. 断线重连机制设计:状态机、心跳与退避策略

3.1 重连的本质是连接状态机

很多初学TCP编程的人会犯一个错误:把重连逻辑做成一个while循环,连不上就sleep一秒然后继续连。这个写法在线程里凑合能跑,但一旦涉及连接状态变化、数据缓存、补传触发这些联动逻辑,就会变得不可维护。

正确做法是把连接生命周期抽象成一个状态机,至少包含四个状态:

  • IDLE:初始状态,当前没有任何连接
  • CONNECTING:正在尝试建立连接
  • CONNECTED:连接已建立,可以收发数据
  • WAITING_RETRY:连接失败或断开,正在等待下一次重试

状态转换的决策逻辑大致是:

  • IDLE收到启动指令,进入CONNECTING
  • CONNECTING成功,进入CONNECTED,同时复位连续失败计数
  • CONNECTED检测到心跳超时或socket异常,进入WAITING_RETRY
  • WAITING_RETRY的等待计时结束,回到CONNECTING
  • CONNECTING失败,记录失败次数,退出WAITING_RETRY

状态机的最大好处是:每一个状态下的行为都是确定的,不会出现“明明断开了还在发数据”这种尴尬。比如在WAITING_RETRY状态下,采集线程照常工作,缓存照常写入,但发送线程必须挂起。数据缓存和连接状态完全解耦。

3.2 心跳机制:TCP层的KeepAlive靠不住,必须自己做应用层心跳

TCP有SO_KEEPALIVE选项,默认空闲2小时才发一个探测包,而且探测失败后还要等若干次才确认连接死亡。对于温湿度采集这种本来就低频发送的场景,SO_KEEPALIVE基本起不到及时断链的作用。

我采用的方案是应用层心跳,两条消息:

  • 设备→服务器:PING,每30秒一次
  • 服务器→设备:PONG

如果设备连续3个PING周期(也就是90秒)没收到对应的PONG,就判定连接失效,主动关闭socket并进入WAITING_RETRY状态。

这里有个细节很容易踩坑:PING和PONG都必须包含一个会话标识或递增序号,用来匹配。否则一个迟到的PONG会被误认为是当前连接的回应,导致状态判断混乱。我在实际项目里见过有同事用简单的PING/PONG字符串,结果服务器端重连后旧连接的PONG延迟到达,设备把新连接的PONG和旧的对上号,误判连接正常。加一个32位递增序号就彻底解决了。

心跳周期怎么定?我的经验是:心跳间隔必须小于网络链路中最短的空闲超时时间。如果不知道具体值,按NAT默认300秒的一半来选比较稳,也就是不超过150秒。再根据“连续失败N次”来判断,一般N取2到3。所以30秒心跳、连续3次失败,90秒判死,这个参数实测下来在公网和跨网段场景都足够灵敏。

3.3 指数退避加抖动:别让一堆设备同时撞车

断线重连最忌讳的是所有设备在同一个时刻疯狂重试。如果现场有上百台采集器,同时掉电又同时来电,如果用固定5秒重连,恢复供电的瞬间网络里全是重连风暴,交换机都可能被冲垮。

正确做法是指数退避:

  • 第1次失败后等1秒
  • 第N次失败后等2^N秒
  • 设置上限,比如最长60秒
  • 加上随机抖动,实际等待时间在计算值基础上乘以(0.8~1.2)

举个例子:第1次失败等1秒,第2次等2秒,第3次等4秒,第4次等8秒,第5次等16秒,第6次等30秒,之后封顶60秒。同时每次加20%以内的随机量。

这个策略的效果:单台设备的恢复时间是秒级,但上百台设备不会集中在同一毫秒发起连接,而是散布在几十秒范围内。实测我们102台设备同时断电重启后,第一条MQTT连接在2秒内建立,最后一条在约90秒内完成,服务器负载完全可控。

3.4 重连成功后的行为:不只是把socket建起来

重连成功容易让人以为“万事大吉”,实际上重连成功后要做的事情比“建立socket”多得多:

  1. 发送一条上线通知,携带设备当前的状态信息
  2. 刷新会话:向服务器端查询最近一条已确认的数据序列号,用来确定续传起点
  3. 触发断点续传:把本地缓存里序列号大于服务器确认点的数据按序补传
  4. 补传完成后,恢复实时数据的正常上报

第二步特别重要。如果不查询服务器端的已确认序列号,设备就只能盲目地把本地缓存全部倒上去,既浪费带宽,也可能重复传大量服务器早就收到的数据。一个简单的GetLatestAckedSeq请求就能让续传有的放矢。

4. 断点续传机制:从缓存设计到可靠确认

4.1 断点续传和“重新上传”的本质区别

这里必须把概念掰清楚:断点续传不是“把所有数据重新上传一遍”。

“重新上传”是笨办法:服务器反正要全量数据,我不管三七二十一全部重发。这在数据量小时看着可行,一旦断线一天、每30秒一条数据,就是2880条,全部重发不仅浪费带宽,还会和实时数据抢占连接,造成“越补越乱”。

真正的断点续传是精确到序列号的增量补传:设备端维护一个“最后推送游标”,服务器端维护一个“最后确认游标”,两者之差就是需要补传的数据区间。服务器已经确认过的数据,一条都不多传;没确认的,一条都不少传。

这个设计在温湿度场景里的效果非常明显:断线2小时=240条数据,补传时每个包压缩后可能10KB就能搞定,几乎是瞬间完成。而且因为只补缺失区间,实时数据的延迟几乎不受影响。

4.2 嵌入式设备上的缓存介质选择:别一上来就上SQLite

温湿度采集器大多是MCU级别设备,资源有限。缓存介质的选择直接影响续传机制的复杂度。

我按设备档次给三种方案:

  • 低端MCU,无文件系统:用Nor Flash或EEPROM,按块写入原始二进制数据。容量一般256KB到4MB,每条约32字节,可以存几千到几万条
  • 中端设备,带SD卡或文件系统:直接写CSV或二进制日志文件,容量宽裕得多
  • 高端边缘网关:可以上嵌入式数据库,但老实说温湿度数据用不上,别把简单问题复杂化

我在这批采集器上选的是Nor Flash方案,存储结构非常直接:

  • 固定分块,每块存一条完整记录
  • 块头部写序列号和写入时间戳
  • Flash剩余空间不足时,最老的未确认数据可以被覆写,同时告警通知服务器“缓存溢出”

这里有个关键判断:要不要覆盖旧数据?我的选择是“宁丢数据,保证设备不死”。传感器采集不能停,缓存如果满了还在继续写,要么设备死机,要么数据全毁。前者更不可接受。所以缓存满了之后,策略是覆盖最老的未确认数据,并在下一次上线时把溢出区间标记为“已丢失”,让服务器知道这段数据不完整,比假装没有发生过强得多。

4.3 数据帧格式:让断点可以被精确定位

断点续传的实现前提是每条数据都有一个可比较的游标。我用的是“设备ID+序列号”双字段定位:

  • 设备ID:区分不同的采集器,默认32位整数
  • 序列号:每条采集记录一个,全局单调递增,重启不重置

序列号有两个作用:一是排序,二是去重。服务器端只要记录每个设备ID下“最大已确认序列号”,就能计算出设备需要补传的区间。

一条补传数据帧的格式大致是:

typedef struct { uint32_t device_id; uint32_t seq; uint32_t timestamp; int16_t temperature; // 单位 0.01℃ int16_t humidity; // 单位 0.01%RH uint16_t flags; // 质量标记 } sensor_record_t;

字段全部定长,好处是解析简单、节省空间、也不需要JSON解析器占用MCU资源。服务器端解析后再转换成JSON或数据库记录即可。

4.4 续传流程:分批上送加ACK游标更新,别一次全发

续传最忌讳一次把几千条数据全部塞进一个TCP包或者一大串MQTT报文里。一旦中途断链,到底是哪些收到了、哪些没收到,又是一笔糊涂账。

我的做法是分批续传:

  • 每批最多100条
  • 每批发送完成后,等待服务器返回ACK,ACK里带上这一批的最大序列号
  • 设备收到ACK后,把本地“最后已确认序列号”更新到ACK值
  • 然后发送下一批
  • 所有批次都确认后,切回实时模式

这个流程虽然保守,但每一步都可恢复。比如传完第3批、共300条后连接断了,服务器已确认到seq=300,设备本地游标也更新到300。重连后,设备只问服务器确认线,服务器返回300,然后从301继续补传。断点续传的“断点”就是这么精确,容错粒度控制在100条以内,通常只有几十条甚至几条。

4.5 幂等设计:重复数据不可怕,缺失数据才可怕

实现续传时,为了避免“万一ACK丢了,设备重传了已经确认的数据”这种情况,服务器端的接收逻辑必须设计成幂等。也就是说,同一序列号的数据传两次,不会产生两条记录,而是以第一次到达的为准。

具体做法是在数据库表里给“设备ID+序列号”建唯一索引,重复插入时直接忽略,或者做UPSERT。这样设备的ACK丢失重传也好、服务器端收到重复数据也好,都不会污染数据。

这个细节我在好几个项目里都被坑过:一开始没做幂等,后来发现服务器数据库里同一秒出现了两条温度记录,而且数值还不一样。排查半天发现是补传和实时上报在时间窗口内重叠了。做了幂等之后,这类问题彻底消失。

5. 现场最容易翻车的四个环节与排查记录

5.1 网线物理断开时,协议栈的真实表现让人迷惑

很多开发者在实验室里用网线断开测试,发现设备在几十毫秒内就感知到了连接断开。真实场景远没有这么理想。

在某个仓库项目里,网线被老鼠咬断了一根芯,物理层处于一个“半断不断”的诡异状态:指示灯偶尔亮,偶尔灭,设备有时能ping通网关,但一到跨网段通信就丢包。我们的设备表现是:TCP连接长期挂在ESTABLISHED状态,心跳偶尔能收到PONG,但实际数据上报成功率只有30%。

这种问题靠应用层心跳不一定能快速识别,因为间歇性通断会“骗过”超时判断。最后的排查方法是加了一个“连续N次数据包往返超时”的计数器。事件概况是:如果连续5次任意类型的网络交互(PING、上报、ACK)都失败,即使心跳没超时,也强制触发重连流程。这个方法实测对半断状态很有效。

5.2 缓存被写穿:断线时间太长,Flash先扛不住了

按30秒一条、每条32字节算,256KB的Flash大概能缓存2700多条,也就是22小时左右。听起来够用,但遇到下面这种情况就崩了:

某项目停电检修设备,恢复供电后运维人员发现设备一直离线,排查发现是断线期间缓存满了,主控在Flash擦除和写入之间反复循环,导致系统看门狗超时,设备反复重启。后续我把缓存策略改成了“缓存满后不再覆写未确认数据,而是停止写入并保留已有数据”。虽然会丢实时数据,但至少保留了一部分历史可用数据,设备也能正常上线。这个场景的选择取决于业务,我倾向于保设备稳定,因为温湿度数据本身重复采集成本很低,但历史数据丢了无法挽回。

之后我又加了一个措施:缓存用量超过80%时,如果链路仍未恢复,就降低采集频率,从30秒降到60秒,极限情况下降到5分钟。这样尽量延长缓存的覆盖时间,换取更多的历史数据。

5.3 设备本地时间戳漂移:补传数据的时间轴可能错位

断点续传时,每条数据都带有设备本地时间戳。但嵌入式设备用的晶振便宜,温漂大,加上没有NTP同步,跑几天就可能差出几分钟。断线期间如果一口气补传240条数据,服务器端按时间戳排序会出现轻微的顺序错乱,甚至和实时数据交错。

解决方案是服务器端对补传数据做“时间轴重对齐”:用设备的序列号作为主排序键,时间戳只作为展示参考。同时在设备端加入NTP对时逻辑,只要链路可用,每天至少对时一次。对时成功后会修正本地时间,但由于序列号是单调递增的,修正时间戳不会影响数据顺序。

这里我特别想强调序列号的一个重要优势:它让数据排序不再依赖时间戳,等于自动免疫了时钟漂移。这也是为什么我在设计数据帧时坚持把序列号放在时间戳之前的排序优先级。

5.4 断电恢复后的“补传风暴”:多台设备同时抢线上报

项目里102台设备同时在线,某次市电闪断又恢复后,几乎同时涌进来全量补传请求。虽然每批100条、间隔时间不长,但在几十秒内服务器的接收线程还是被打满了,数据库写入队列一度积压到几万条。

解决办法分两头:

  • 设备端:补传时增加一个随机的启动延迟(0~30秒),避免大家同时涌进来
  • 服务器端:接收接口前加一层内存队列,削峰填谷,入库改为批量写入,每次事务提交100~500条

实测效果很理想,补传风暴从几十分钟缩短到一两分钟,服务器CPU峰值从85%降到35%。设备端的“随机延迟补传”是成本最低、收益最大的一个改动。

6. 这套设计在真实项目里跑出来的数据

项目最终交付时的关键指标:

  • 102台以太网温湿度采集器,30秒上报周期,Modbus TCP、MQTT、HTTP三通道按项目配置切换
  • 连续运行3个月,设备在线率从最初的96%提升到99.95%,月掉线次数从30多次降到1~2次
  • 断线2小时以内的数据续传完成率100%,断线24小时以内完成率大于98%,未完成部分主要是缓存溢出导致的数据丢失
  • 服务器端接入延迟从补传风暴高峰期的分钟级恢复到秒级

这些数字不能说惊艳,但确实是在真实现场跑出来的,比实验室里好看的结果可靠得多。

我在实际项目中最大的体会是:以太网温湿度采集的“技术难度”不高,难的是把断线重连、断点续传、多协议适配、缓存管理、幂等处理这些细节串成一个整体。每一个环节单独看都很简单,但它们之间的状态联动才是真正容易出错的地方。建议大家都用状态机把逻辑先画清楚,再动手写代码,能少走很多弯路。

最后分享一个小技巧:设计断线重连机制时,可以人为构造“断电重启、网线抽拔、交换机重启、服务器重启、NAT超时”五种故障,每种故障测试一遍。能把这五种故障全部跑通,这套通讯机制在绝大多数现场就不会有太大问题了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 7:04:40

PLC数据上云实战:网关+MQTT+Node.js构建Web SCADA监控

1. 从车间到浏览器:这套方案到底在解决什么问题车间里一台台达PLC跑了三年,温度PID参数调了无数遍,操作工还是得站在电柜前面盯着触摸屏。老板想在中控室的大屏上看实时数据,还想用手机查历史曲线,更想在下班后收到微信…

作者头像 李华
网站建设 2026/10/1 7:04:33

医学图像分割实战:从CNN到Transformer的架构演进与调优指南

1. 医学图像分割的技术演进与核心挑战医学图像分割这个方向,我从几年前做肝脏肿瘤勾画开始接触,到后来做视网膜血管提取、细胞核分割,一路踩坑过来。早期用纯 CNN 方案,后来逐步过渡到 Transformer 架构,中间还试过 CN…

作者头像 李华
网站建设 2026/10/1 7:04:02

为啥医院喜欢给开煎好的药物,不愿意让病人自己煎药

医院更愿意给煎好的药,核心原因不是嫌麻烦,而是为了保证药效和用药安全。煎药看着简单,但里面门道不少,自己在家煎容易出错,直接影响治疗效果,甚至可能带来风险。 🏥 医院为什么更推荐代煎 1. 药材质量更可控:医院药房的药材有统一采购和质量把关,而自己去外面抓药…

作者头像 李华
网站建设 2026/10/1 7:03:43

大模型对比新思路:用TaoToken统一Key实测Perplexity-AI、POE与ChatGPT

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

作者头像 李华