news 2026/10/6 3:14:34

从TCP到HTTP:网络IO性能优化的分层排查与实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从TCP到HTTP:网络IO性能优化的分层排查与实战指南

最近我碰到一个挺典型的报错,同事把日志贴到群里问了一圈:Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http。乍一看是镜像源的问题,有人让他换源,有人让他重启Docker,折腾半天没解决。后来我在宿主机上用 tcpdump 抓了一把包,才发现问题根本不在 HTTP 层——SYN 包一连重传了五次,TCP 连接压根没建立起来。这种场景我遇到太多次了:表面上是 HTTP 层报错,根子却埋在更底层的 TCP 上。所以这次我把网络IO性能优化的思路从头捋一遍,从 TCP 握手、协议栈参数,到 HTTP 连接复用和超时配置,每一层都有可以优化和排查的地方。适合后端开发、运维、容器平台使用者,以及做移动端网络优化的朋友参考,至少能帮你在下次遇到类似报错时少走弯路。

这个标题看起来很长,但核心就一句话:当你的应用访问外部服务变慢、连接失败、或者请求大量超时的时候,不要急着去调业务代码,先把 TCP 到 HTTP 这条链路一层层拆开看。整个排查和优化过程并不神秘,掌握几个关键参数和抓包技巧,大部分问题都能定位到具体某一层。

1. 先把问题分层:为什么报错五花八门,揪出来都是同一根藤

1.1 从热词看真实痛点:那些让你头皮发麻的报错长什么样

我在整理相关资料时发现,网上搜“网络IO性能优化”,高频出现的其实是各种具体的报错经验。比如:

  • error response from daemon: get "https://registry-1.docker.io/v2/": net/http
  • harbor 推送失败 get "https://192.168.209.133/v2/": dial tcp 192.168.209.133:
  • error response from daemon: ports are not available: exposing port tcp 0.0.0.0
  • java tcp客户端重连时报地址已在使用
  • http error 400. a request header field is too long.

这些报错分布在 TCP 和 HTTP 两层,但很多人一开始只会盯着最上层的错误提示。比如net/http这个关键字一出现,就以为是 Go 的 HTTP 客户端配置问题,其实net/http只是把底层错误包了一层皮往上抛。真正的原因可能是 TCP 握手超时、连接被对端重置、TLS 握手失败,甚至只是本机端口被占满。

所以优化网络IO的第一步,不是调参数,而是学会分层。把整个数据通路想象成一条水管:TCP 负责把水管本身接好、保证水流不丢,HTTP 负责决定水怎么分装、每次要接多少桶。你要先判断是水管没接上,还是装水的方式效率太低。

1.2 为什么偏偏是 TCP 和 HTTP 这两层

几乎所有面向用户的网络服务都跑在 HTTP 之上,而 HTTP 又几乎总是跑在 TCP 之上。这就导致 TCP 层出的问题必然以 HTTP 错误的形式暴露出来,HTTP 层的低效则会让 TCP 层白白背锅。

TCP 层关注的是连接能不能建立、丢包重传多不多、带宽时延是否合理。HTTP 层关注的则是请求复用够不够、超时设置合不合理、连接池是否被耗尽。这两层互相依赖:TCP 握手都完成不了,HTTP 再怎么调连接池也没用;反过来,TCP 很稳但 HTTP 每次请求都重新建连,那吞吐量一样上不去。

有基础的同学都知道 TCP 三次握手和四次挥手,但很少有人意识到握手本身的成本有多高。一个普通的跨机房请求,TCP 握手要消耗一个 RTT,TLS 如果要开启,还要额外两到三个 RTT。换句话说,如果一个客户端频繁建立新连接,光是握手就要白扔几个网络往返时间。这也是为什么 HTTP keep-alive、连接池这类机制如此重要——它们本质上就是把 TCP 握手的成本摊薄到很多次请求上。

排查原则:先确定错误发生在哪一层,再谈优化。TCP 层的问题多表现为“连不上”“很慢”“断断续续”,HTTP 层的问题多表现为“请求超时”“返回错误码”“连接复用率低”。

2. TCP 层优化:三次握手、排队与连接回收

2.1 三次握手到底贵在哪里,TFO 又是怎么省时间的

先说一个很直观的计算。客户端发送 SYN,服务端回复 SYN-ACK,客户端再回 ACK,这是标准三次握手。在本地回环上,这个过程可能也就零点几毫秒,完全没感觉;但在跨地域、跨运营商、甚至跨海的链路上,一个 RTT 可能就是几十上百毫秒。如果业务代码里每次请求都新建 TCP 连接,高并发时大量时间都耗在握手和数据传输之间的空隙上了。

要优化新连接建立,有一个被低估的方案叫 TCP Fast Open,也就是 TFO。它允许客户端在 SYN 里直接携带数据,把原本“握手完成后再发请求”的流程压缩到一次往返里。Linux 下可以通过net.ipv4.tcp_fastopen开启,有三档取值:1 表示客户端可用,2 表示服务端可用,3 表示两端都启用。这个参数对短连接场景特别有效,比如小请求、API 调用频繁的应用。

不过 TFO 也有代价:它需要客户端和服务端通过 cookies 验证,中间经过 NAT 设备时可能被丢弃,某些防火墙也会直接拦截带数据的 SYN。所以我的建议是:在内网低延迟环境意义不大,跨地域高 RTT 环境才值得开。普通场景先把连接复用做好,远比 TFO 实在。

另一个经常被忽略的是 Nagle 算法。它会把小的数据包攒到一起再发送,本意是减少网络拥塞,但对于需要低延迟的请求来说就是灾难。你和服务器交互一个几十字节的小请求,却要等缓冲区攒够了才发出去,延迟凭空变高。所以在写 TCP 程序时,如果确认是交互式请求,通常要设TCP_NODELAY关闭 Nagle 算法。这个心得很重要,因为很多开发者只调了超时参数,把 Nagle 完全忘在脑后。

2.2 协议栈参数调优:哪些能改,哪些不能乱动

TCP 协议栈的参数在网上随便一搜就是一大把,但真正该动的没几个。我一般在/etc/sysctl.conf里只动这些:

# 应对高并发连接突增,开启 SYN Cookie net.ipv4.tcp_syncookies = 1 # 提高 SYN 队列长度,避免握手请求被丢弃 net.ipv4.tcp_max_syn_backlog = 4096 net.core.somaxconn = 4096 # 加快 TIME_WAIT 状态的回收 net.ipv4.tcp_fin_timeout = 30 # 允许客户端复用处于 TIME_WAIT 的连接,仅在发起连接的一端开启 net.ipv4.tcp_tw_reuse = 1 # 调节 TCP keepalive 探测时间 net.ipv4.tcp_keepalive_time = 600 net.ipv4.tcp_keepalive_intvl = 75 net.ipv4.tcp_keepalive_probes = 9

逐条说下为什么是这些值。tcp_syncookies=1解决的是 SYN 洪水或者瞬间连接暴增导致握手队列满的问题。正常情况队列满了新连接就该被丢弃,客户端表现为“连接超时”,开 syncookies 之后,即使队列满了也能通过 cookie 机制临时建立连接。

tcp_max_syn_backlog和somaxconn分别控制内核 SYN 队列和应用层 accept 队列的长度。如果你的服务用 Nginx 作为入口网关转发 TCP 流量,somaxconn太小会导致高并发下连接被拒。调大这两个值不会引入什么副作用,但注意要看一下服务的 backlog 配置是否同步调大了,否则应用层还是只能 accept 那么多连接。

tcp_fin_timeout和tcp_tw_reuse是针对 TIME_WAIT 的。TIME_WAIT 本身是 TCP 协议为了保证网络中的延迟报文不干扰新连接而设计的,正常情况下不应该乱砍。但如果客户端频繁发起短连接,积压大量 TIME_WAIT,会导致端口资源紧张,这时tcp_tw_reuse可以允许客户端在新的连接里复用这些连接,注意它只对主动发起连接的一端有意义,服务端开这个参数几乎没用。

提醒:生产环境改 sysctl 之前先看清楚参数作用范围。tcp_tw_reuse不要和tcp_tw_recycle混淆,后者在 NAT 环境下会导致连接被随机重置,现代内核基本不建议再开。

2.3 端口耗尽的真相:为什么报“address already in use”

有一类报错和端口耗尽相关,比如热词里那个ports are not available: exposing port tcp 0.0.0.0,以及 Java 客户端重连时的地址已在使用。背后机制是同一个:TCP 连接用四元组唯一标识,也就是“源 IP + 源端口 + 目标 IP + 目标端口”。客户端发起连接时,需要从本机临时端口范围内挑一个空闲端口。

Linux 默认临时端口范围通常在 32768 到 60999,也就是大概两三万个可用端口。如果客户端在短时间内建立了大量短连接,并且这些连接都进入 TIME_WAIT 状态,可用的源端口就会被占满,新连接自然建不起来,报错就是address already in use。

这时候除了调快 TIME_WAIT 回收,还有一个思路是扩大临时端口范围:

net.ipv4.ip_local_port_range = 1024 65535

但要注意,端口范围只是理论上限,实际还受到文件描述符数限制。所以排查时我一般先看几个数据:ss -s看系统 socket 统计,ss -ant state time-wait看具体 TIME_WAIT 数量,再cat /proc/sys/net/ipv4/ip_local_port_range看端口范围。三者一起看才能确定瓶颈是端口、描述符还是其他原因。

这里本着实操角度补充一个抓包技巧。tcpdump是排查 TCP 问题最直接的工具,不需要抓得很全,关键是抓住 SYN 重传、Dup ACK、RST 这些关键信号:

tcpdump -i eth0 host 192.168.1.10 and port 5000 -w tcp.pcap

抓完用 Wireshark 打开,看 TCP 流的交互过程。如果看到客户端连续重传 SYN,但服务端一直不回复,多半是链路问题或者防火墙丢包;如果收到 RST,那就是服务端直接拒绝了连接,可能是端口没监听或者安全策略拦截。这些信号比任何监控面板都直观。

3. HTTP 层优化:连接复用、超时配置与真实错误处理

3.1 HTTP 连接复用为什么是性能优化的分水岭

很多团队在优化网络性能时会陷入一个误区:疯狂调 TCP 内核参数,但业务代码里每次请求都新建连接。TCP 参数调得再好,也扛不住你一分钟内建立上万个短连接。真正的分水岭是 HTTP 层的连接复用。

HTTP/1.1 的 keep-alive 机制让多个请求可以复用同一条 TCP 连接,避免重复握手。但 HTTP/1.1 在同一连接上只能串行处理请求,一个请求没结束,后面的只能排队。这就有了 HTTP/2 的多路复用,允许在一条连接上并行发送多个请求,每个请求有独立的流 ID,互不阻塞。

不过 HTTP/2 也有自己的痛点:虽然应用层多路复用了,底层还是 TCP 的字节流,一旦某个包丢失,所有复用的请求都得等重传完成,这就是常说的“TCP 上的队头阻塞”。所以 HTTP/2 不是银弹,连接池管理和合理的请求并发数量依然很重要。

对于大多数后端服务来说,最值得做的是为 HTTP 客户端配置合适大小的连接池。连接池太小,高并发时请求要排队等空闲连接;连接池太大,又会占用大量文件描述符和内存。一个常见的起始配置是:最大空闲连接数设置为业务并发峰值的 10% 到 20%,空闲超时时间设置为 60 到 90 秒,避免连接被中间网关提前断开后又浪费资源重建。

3.2 超时配置的艺术:别让客户端无限等下去

超时配置是 HTTP 层最容易出问题的地方,没有之一。很多人只设置了Timeout一个参数,觉得这样就够了,实际上 HTTP 请求的整个生命周期里,每段都有独立的超时。以 Go 的net/http客户端为例:

transport := &http.Transport{ DialContext: (&net.Dialer{ Timeout: 5 * time.Second, KeepAlive: 30 * time.Second, }).DialContext, TLSHandshakeTimeout: 5 * time.Second, ResponseHeaderTimeout: 10 * time.Second, IdleConnTimeout: 90 * time.Second, MaxIdleConns: 64, MaxIdleConnsPerHost: 16, } client := &http.Client{ Transport: transport, Timeout: 15 * time.Second, }

这里每一项超时解决的是不同问题。DialContext控制 TCP 三次握手的等待时间,如果设置得太短,正常跨地域连接都可能超时;TLSHandshakeTimeout控制 TLS 握手,证书校验、密钥协商都在这段里;ResponseHeaderTimeout控制服务端返回响应头的等待时间,如果服务端处理请求很慢,这个参数决定了客户端何时放弃;IdleConnTimeout控制空闲连接在池子里的存活时间。

实践中我见过大量线上问题都是因为没设置ResponseHeaderTimeout,默认值其实是无限等待。下游服务进程卡死,客户端就跟着卡住,最后线程池、协程池全被占满,整个服务雪崩。所以超时配置一定要分角色思考:你是调用方,就要给每一段都加超时;你是被调用方,就要保证自己下游超时的时间小于上游等你的时间。

3.3 从报错反推:Docker 推送失败背后的 HTTP 语义

再回到开头的那个 Docker 报错。Error response from daemon: Get "https://registry-1.docker.io/v2/"这个错误信息是 Docker CLI 直接透传的。Docker 在推送或拉取镜像时,先要访问 registry 的/v2/接口完成版本协商和认证。这一步本质上是一个 HTTP GET 请求,一旦网络不通或者 TLS 握手失败,Docker 就把底层错误原样抛出来。

我有一次遇到的情况是:registry 服务本身没毛病,但办公室网络对出方向连接有 QoS 限制,到 registry-1.docker.io 的丢包率接近 30%。TCP 层在反复重传,HTTP 层自然等不到响应,最后客户端超时报错。还有一次是内网 Harbor 服务所在的机器证书过期了,TLS 握手失败,但日志里看到的还是dial tcp ... connection refused之类的 TCP 层错误,把很多人带偏了方向。

所以要学会读报错信息里的关键字。看到dial tcp ... timeout,是连接建立超时,偏向网络层面;看到connection refused,是服务端端口没监听或主动拒绝,偏向服务层面;看到EOF,是连接建立后被中断或读取响应时到达了末尾,偏向网关或 TLS 层;看到net/http: TLS handshake timeout,那基本就是证书或加密协商问题了。

4. 三个实战案例:从现象到定位再到修复的完整路径

4.1 案例一:Docker Hub 推送镜像一直卡住,最后超时

现象:docker push推送镜像时,进度条长时间停在准备阶段,最终报出net/http: request canceled。

排查过程:我先看宿主机网络,ping和curl都不稳定,但不能只靠这个下结论。用 tcpdump 抓包后,看到客户端发出的 SYN 包重传了 5 次,RTO 从 1 秒指数增长到 16 秒,服务端完全没有响应。这就把问题锁定到了网络链路上,和 Docker、HTTP 配置都无关。再检查 MTU,发现宿主机网卡和交换机之间的 MTU 不一致,大包上不了,小包能通,导致 TCP 窗口扩大后整个连接就断了。

解决:把宿主机 MTU 改成和交换机一致,同时给 Docker daemon 配置了 registry-mirrors 作为兜底。这里也提醒大家,遇到 Docker 报错不要条件反射地换加速源,先分清是网络链路、DNS、还是 registry 服务本身的问题。

4.2 案例二:Harbor 推送镜像报 dial tcp connection refused

现象:内网推送到 Harbor 时报dial tcp 192.168.209.133:443: connect: connection refused。

很多人看到 connection refused 就去查防火墙,其实这个错误本身已经说明 TCP 层收到了 RST 包,而不是丢包超时。接下来要确认的是服务端谁在拒绝。我在服务器上执行ss -lntp | grep 443,发现监听的是 80 端口的 HTTP 服务,443 根本没有进程监听。再往前查,Harbor 的 nginx 容器启动失败,因为宿主机上的 Docker 版本和 Harbor 要求的不兼容。把容器修好后,问题解决。

这个案例说明一个问题:TCP 层的“拒绝”和“超时”是两种完全不同性质的表现,前者通常意味着目标端口不可达或主动拒绝,后者意味着链路不通或防火墙丢包。排查方向完全不一样。

4.3 案例三:端口映射失败,exposing port TCP 0.0.0.0

现象:启动容器时提示ports are not available: exposing port TCP 0.0.0.0:5000: listen tcp 0.0.0.0:5000: bind: address already in use。

这个报错非常直白:宿主机上的 5000 端口已经被占用了。很多人的第一反应是重新找个端口,但如果你想知道是谁占用的,用这个命令:

ss -lntp | grep 5000

有一次我发现占用 5000 端口的是一个旧的 docker-proxy 进程,是之前某个容器残留的。这个进程属于早期 Docker 版本在 iptables 和用户态端口转发之间切换时留下的僵尸进程。杀掉之后端口释放,问题解决。另外一种常见情况是改了 Docker 的 iptables 规则,导致容器端口映射失败,但宿主机端口实际是空闲的,这时候要检查 Docker 的 iptables 链状态。

小贴士:遇到端口类问题,先分清楚是“端口监听冲突”还是“Docker 代理绑定失败”。前者用 ss 找进程,后者要查 docker daemon 日志和 iptables 状态。

5. 不止服务端:移动端和嵌入式环境下的网络IO优化

5.1 移动端弱网场景:连接不是越频繁越好

说到网络IO优化,普遍关注的都是服务端,但移动端同样重要。手游性能优化里最常见的瓶颈之一就是“弱网下的请求超时和重传风暴”。移动网络的 RTT 波动大,经常从 20 毫秒直接跳到 1 秒以上,TCP 本身的拥塞控制算法在快速变化的环境中表现并不稳定。

移动端的优化思路和服务端不太一样。服务端偏向调协议栈和连接池,移动端应该偏向减少无谓连接和请求。比如做 DNS 缓存,避免每次请求都走一次 DNS 解析;做请求合并,把多个小请求合并成一个大请求;做预连接,在用户进行某个操作之前提前完成 TCP 和 TLS 握手。此外还要设计好重试策略,不能用固定时间间隔无限重试,应该采用指数退避并加上随机抖动,防止大批客户端同时重试把服务端打垮。

我见过不少移动端团队在后台把connectTimeout设置成 30 秒,认为这样能提高成功率,实际上是灾难级的决策。移动端网络切换频繁,弱网时让用户等 30 秒毫无意义,通常 5 到 8 秒的连接超时加上 10 秒的请求超时已经足够。如果真需要长任务,应该用异步队列而不是阻塞等待。

5.2 嵌入式与工控协议:TCP 优化未必围绕 HTTP 展开

热词里有不少和 Modbus TCP、STM32 HTTP 库、LabVIEW 与实时机 TCP 交互相关的搜索,这些场景和互联网后端差异很大。嵌入式环境资源有限,TCP 优化往往集中在几个点上:调整缓冲区大小、确认 keepalive 是否开启、处理 TCP 粘包问题。

Modbus TCP 这种工业协议通常是短小报文、高频交互,对延迟极其敏感。在这种场景下,Nagle 算法的影响非常明显,必须开启TCP_NODELAY;同时因为报文没有应用层长度前缀,粘包拆包的处理逻辑直接决定协议可靠性。另一个容易踩的坑是嵌入式设备的 TCP 栈在校验和、重传定时器上的实现不规范,跨平台互通时经常表现为“时好时坏”。遇到这类问题,用抓包对比正常设备和不正常设备的报文差异,是最快的定位方式。

这些经验换个角度讲,也说明了网络IO优化不是只有互联网公司才需要。只要你写了 TCP 代码,无论跑在服务器上还是单片机上,都要把连接建立、数据边界、超时退避这些基本功想清楚。

6. 常见问题速查表与个人排坑心得

6.1 一张表看清报错、原因和排查方向

报错或现象可能原因排查方向与建议
dial tcp ... connection refused目标端口未监听、服务挂掉、安全策略拒绝ss -lntp查监听,确认服务和端口
dial tcp ... i/o timeout链路丢包、防火墙丢 SYN、MTU 问题抓包看 SYN 重传,检查网络质量
net/http: TLS handshake timeoutTLS 握手慢、证书验证卡住检查证书链、本地时间、TLS 版本协商
EOF出现在响应读取阶段连接被网关中断、空闲超时、服务端崩溃看服务端日志,调整代理空闲超时
address already in useTIME_WAIT 过多或端口范围不足统计 TIME_WAIT,调整端口范围或启用 reuse
ports are not available宿主端口被占用或 docker-proxy 绑定失败ss -lntp找占用进程,查 docker 日志
HTTP 400 request header field too long请求头或 Cookie 超出服务器限制调 Nginx 的 large_client_header_buffers
连接复用率低、请求排队严重连接池太小、keep-alive 时间太短观察线程和连接池状态,合理扩容
跨地域访问很慢但抓包正常TLS 会话未复用、TCP 握手 RTT 高开启 TLS 会话复用,考虑就近接入

这张表不可能覆盖所有情况,但 90% 的网络IO问题都可以先从这几类里对号入座,再去做深入排查。

6.2 我的排坑方法论:永远先分层,再动手

排查网络IO性能问题,我的固定步骤是这样的。先确认范围:是单机问题还是全集群问题,是到某一个目标地址有问题还是所有外网都慢。然后确认现象:超时、拒绝、还是性能低。接着抓包看 TCP 层的握手和重传数据,确定链路是否存在问题。如果 TCP 层信号正常,再进入 HTTP 层,看连接复用、超时配置、DNS 解析和 TLS 耗时。最后才是看业务代码有没有低效逻辑。

这套流程听起来啰嗦,但能在最短的时间内避开“改超配置碰运气”的坑。我见过太多人一上来就先调超时时间,把Timeout从 3 秒改到 60 秒,报错解决了,其实只是把问题掩盖得更深了,高峰期还是会出事。

另外一个经验是:监控指标一定要覆盖连接建立耗时和连接复用率。这两个指标比单纯看 P99 延迟要早一步发现问题。连接建立耗时突然升高,说明网络或握手层出现瓶颈;连接复用率下降,说明 keep-alive 或连接池设置开始不适配当前流量模型。有了这两项指标,网络IO性能优化就从“救火”变成了“预防”。

做网络IO优化这几年,我最大感受是:不要被报错信息里最显眼的那个词带偏。net/http只是 Go 标准库的名字,不代表问题出在 HTTP 层;connection refused也不意味着服务端一定挂了。从 TCP 到 HTTP 一层层剥开,每一步都要有数据和抓包证据支撑,这才是性能优化该有的姿势。如果你现在手头正好有一个“网络慢”或者“超时”的疑难问题,不妨按这个思路把每一层的数据都拉出来看看,多半会有新的发现。

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

10类水稻害虫检测数据集:VOC格式解析与YOLO训练实战指南

简介:面向目标检测与农业害虫识别场景,这份水稻害虫检测数据集采用VOC标注格式,涵盖10个害虫类别,并附类别json字典与可视化脚本,可直接用作目标检测数据集。压缩包共2000个文件,以1999个XML标注为主&#…

作者头像 李华
网站建设 2026/10/6 3:13:56

从macOS迁移到Linux:备份失效与UI卡顿后的完整避坑指南

作为一个长期在 macOS 上写代码、做设计、剪视频的重度用户,我这次是真的被逼走了。不是没给过机会,各个大版本的所谓“丝滑”我没少体验,但自从某次外接硬盘上的 Time Machine 备份在恢复时被系统判定为“无可用备份”之后,我对它…

作者头像 李华
网站建设 2026/10/6 3:12:44

Java驱动包统一Modbus、Bacnet与OPC-UA,简化工业设备接入

简介:一套基于 Java 的物联网(IOT)通用驱动包设计源码,主要面向需要对接 Modbus-TCP、Bacnet、OPC-UA 等协议的 Java 开发者与系统集成商。驱动包以 SDK 方式组织,高度模块化,便于快速嵌入业务系统&#xf…

作者头像 李华
网站建设 2026/10/6 3:12:38

麒麟桌面系统V10-SP1用户组全攻略:权限配置与实操命令解析

用了好几年麒麟桌面系统,从V10早期版本一路用到现在V10-SP1 2503,日常给同事处理得最多的,除了软件装不上,就是各种权限说人话。报个“权限不足”,查来查去,十有八九是用户没进对用户组。这篇文章就把麒麟桌…

作者头像 李华
网站建设 2026/10/6 3:12:15

工业数采网关实战:MQTT与Modbus-RTU桥接RS485设备

先交代个背景。我最近把手头一个工业数采网关项目的 MQTT 上行链路做完了,上一篇写的是环境搭建和订阅发布的基础流程,这篇把最常被问到的问题展开聊:MQTT 消息到底怎么变成 RS485 串口上的一帧数据发给仪表,仪表回应回来的数据又…

作者头像 李华
网站建设 2026/10/6 3:12:03

半天上线AI Agent技能分享站:从架构到SEO的实战记录

事情得从办公室那声“老登”说起。我组里几个年轻人,平时管我这个工作十二年、现在主攻 AI 应用落地的人叫“老登程序员”。上个月我花半天时间把 agentskill.work 从空白仓库做到全量上线,回来之后他们再喊这个称呼,我答应得比谁都快。这个项…

作者头像 李华