Linux网络编程实战:TCP连接管理、epoll与粘包拆包全解析
很多人学Linux网络编程印象最深的就是那几行socket调用socket、bind、listen、accept、connect。第一次跑通TCP通信demo的时候都觉得这东西没多难。可真把这段代码扔到线上让它顶住真实流量各种古怪问题就全冒出来了——连接卡住几百毫秒就超时、服务端莫名其妙多出一个不可用进程、客户端偶发收到半截数据。这篇文章我想把这些年做Linux网络编程沉淀下来的经验系统梳理一遍重点放在TCP通信从建立到关闭的全过程给正在学socket编程的朋友一些实验课上学不到的东西。1. 从tcpdump看三次握手TCP连接建立的真相TCP通信最容易被忽视的地方恰恰是它的起点连接建立。很多人写代码时默认connect一返回连接就是好的但真实网络里一次握手可能丢包、可能超时、可能被对端直接拒绝。我会从抓包的角度把这一过程看清楚。1.1 抓包观察SYN、SYN-ACK、ACK连接不是瞬间建立的假设你在一台Linux机器上启动了一个监听8080端口的服务然后用客户端去连接。在服务端和客户端同时跑tcpdump抛开环回接口常见三次握手的抓包长这样18:56:12.345678 IP 192.168.1.100.54321 192.168.1.200.8080: Flags [S], seq 1234567890 18:56:12.345712 IP 192.168.1.200.8080 192.168.1.100.54321: Flags [S.], seq 987654321, ack 1234567891 18:56:12.345755 IP 192.168.1.100.54321 192.168.1.200.8080: Flags [.], ack 987654322第一行是客户端发出的SYN请求建立连接第二行是服务端回应的SYN-ACK既确认了客户端的SYN也携带了自己的初始序号第三行是客户端对服务端SYN的确认。经过这三步连接状态才从SYN_SENT变成ESTABLISHED。这个过程对应到内核是两条队列配合完成的。服务端收到SYN后连接进入半连接队列SYN队列此时状态是SYN_RECV收到客户端最后的ACK后连接从半连接队列移到全连接队列accept队列状态变成ESTABLISHED等accept()把它取走。如果SYN队列溢出新连接直接被丢弃如果accept队列溢出内核会把多余的连接drop掉客户端看到的现象就是connect卡住或者被拒。我推荐你把tcpdump作为学TCP通信的标配工具而不是只在排查故障时才想起它。亲自抓几次包看到SYN重传、看到RST复位、看到延迟ACK你对connect超时、连接被拒绝这类问题会有一张视觉记忆排查问题时心里踏实得多。1.2 教学代码与生产环境的差距在哪里教科书上的TCP通信代码通常长这样服务端accept后read客户端connect后write看起来干净利落。但在生产环境这段代码至少缺了三样东西。一是错误处理。read返回-1不一定是致命错误可能是被信号打断EINTR也可能是非阻塞模式下暂时没有数据EAGAINconnect返回-1也不一定是网络不通可能是连接被对端RST。很多人写代码只判断小于0就是失败结果线上偶发异常时完全摸不着头脑。二是缓冲区管理。TCP是流协议数据到达的顺序是可靠的但到达的边界毫无保证。你一次write 10KB对端read可能分三次才读完你连续两次write对端可能一次read就全部收走。后面第五节会详细说拆包的问题。三是超时与生命周期。一个连接长时间不发数据它到底是活着还是死了TCP有keepalive机制但默认参数是7200秒才开始探测对绝大多数业务来说等于没有。连接建立后谁来负责关闭、怎么优雅关闭代码里往往没有规划。把这些补全一个能跑的demo才慢慢变成能扛的服务。下面几个章节我会把它们逐个拆开讲。2. 服务端骨架socket、bind、listen三个调用背后的事服务端编程的第一步是创建监听套接字。我见过不少人在socket和bind之间踩坑之后从此只用模板代码出了问题全靠重启。其实这三个调用每个都有值得深挖的细节。2.1 socket()的协议族参数AF_INET与AF_UNIX怎么选socket()的第一个参数是协议族最常见的是AF_INETIPv4和AF_INET6IPv6。如果只是本机进程间通信还有一个被忽略的选择AF_UNIX也叫AF_LOCAL。AF_UNIX套接字不走TCP/IP协议栈不需要IP和端口而是通过文件系统路径寻址比如/tmp/mysql.sock。它的优势是性能高、无网络开销缺点是只能本机使用。判断依据其实很简单你的服务需要被外部机器访问选AF_INET或AF_INET6只是同机不同进程通信优先考虑AF_UNIX。第二参数SOCK_STREAM对应流式套接字即TCPSOCK_DGRAM对应数据报套接字即UDP。第三个参数通常是0表示让内核选择该协议族下与类型匹配的默认协议。注意不要只关心AF_INET和SOCK_STREAM第二个参数选错会导致行为完全不同——比如SOCK_DGRAM下你调connect()语义完全变样send数据时不需要对方的地址。2.2 bind()与Address already in use的恩恩怨怨bind()把套接字和一个地址结构绑定地址结构用sockaddr_in表示。很多初学的代码会在这里写错字节序端口号必须用htons()转成网络字节序IP地址可以用inet_pton()转换。下面是一个标准的绑定写法int listen_fd socket(AF_INET, SOCK_STREAM, 0); if (listen_fd 0) { perror(socket); return -1; } int opt 1; setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, opt, sizeof(opt)); struct sockaddr_in addr; memset(addr, 0, sizeof(addr)); addr.sin_family AF_INET; addr.sin_addr.s_addr htonl(INADDR_ANY); // 监听所有网卡 addr.sin_port htons(8080); if (bind(listen_fd, (struct sockaddr *)addr, sizeof(addr)) 0) { perror(bind); close(listen_dd); return -1; }这里有个最常见的坑服务端重启时报Address already in use。原因是连接关闭时主动关闭方会进入TIME_WAIT状态持续2MSL默认60秒左右。你的服务端作为主动关闭方时端口会被TIME_WAIT占住直接bind会失败。解决办法就是我在代码里写的setsockopt设置SO_REUSEADDR它允许在TIME_WAIT状态下重新bind同一端口。关于TIME_WAIT还有一个常见的心理误区看到大量TIME_WAIT就紧张。实际上面向高并发的服务端如果要主动断开连接比如超时踢掉空闲连接TIME_WAIT是正常现象。需要用tcp_tw_reuse、tcp_tw_recycle这类内核参数时更要谨慎tcp_tw_recycle在NAT场景下会引发诡异问题现在已经不推荐开启。稳妥的做法是接受TIME_WAIT的存在通过合理的连接生命周期管理把数量控制在合理范围。2.3 listen()的backlog并发连接涌进来时队列怎么扛listen()的作用是让套接字进入监听状态第二个参数backlog历来有争议。误区在于很多人以为backlog是最大连接数其实从Linux 2.2开始它只控制全连接队列accept队列的长度上限。当客户端完成三次握手但服务端还没调用accept()时连接就暂时躺在全连接队列里。如果accept()处理速度跟不上连接到达速度队列就会满内核随后丢弃新到达的连接。这个队列上限还受系统参数/proc/sys/net/core/somaxconn限制默认4096即使你listen(10240)最终上限也可能是4096。服务端典型的主循环代码是这样的while (1) { int conn_fd accept(listen_fd, NULL, NULL); if (conn_fd 0) { if (errno EINTR) continue; perror(accept); break; } handle_conn(conn_fd); }注意accept()阻塞时被信号打断会返回EINTR这个错误不能当作致命错误处理否则一个信号就可能导致整个服务退出。我见过好几个生产事故就是这里只写了perror和break然后莫名其妙地重启。3. 客户端connect超时、重试与优雅关闭服务端代码写得再健壮客户端也有一堆自己的坑。尤其是connect()这个调用默认是阻塞的它在网络不通时会一直卡到内核超时这个超时时间可能长达两分钟业务等不了。3.1 阻塞connect卡住整个线程时怎么办默认情况下connect()本质上是把套接字置于正在连接状态然后等待握手完成或超时。对本地回环来说连接几乎是瞬时的。但如果目标IP是不通的网段connect()可能等上100多秒才返回ETIMEDOUT。在单线程程序里这段时间什么都干不了。如果你用的是多线程模型等于是白白占着一个线程。解决思路有两个要么把connect放进专门的连接线程池要么用非阻塞connect配合poll实现自己的超时逻辑。生产上后一种方案更常见因为它把连接中也变成了一种可以被事件循环管理的状态。3.2 非阻塞connectpoll实现可控超时核心思路是先把套接字设为非阻塞再调用connect()。此时connect()会立即返回-1并且errno为EINPROGRESS表示连接正在进行。接下来用poll或select等待POLLOUT可写事件并传入你想要的超时时间。int connect_with_timeout(int fd, struct sockaddr *addr, socklen_t len, int timeout_ms) { int flags fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK); int ret connect(fd, addr, len); if (ret 0) { return 0; // 连接立即完成 } if (errno ! EINPROGRESS) { return -1; // 真正失败ECONNREFUSED、ENETUNREACH等 } struct pollfd pfd; pfd.fd fd; pfd.events POLLOUT; int pr poll(pfd, 1, timeout_ms); if (pr 0) { return -1; // 超时或poll被信号打断 } int err; socklen_t elen sizeof(err); getsockopt(fd, SOL_SOCKET, SO_ERROR, err, elen); if (err ! 0) { errno err; return -1; // 连接失败比如对端RST } return 0; }这段代码里有两个关键点。第一poll返回POLLOUT后连接不一定成功必须用getsockopt(SO_ERROR)取真正的错误码。第二超时返回后这个套接字不能再用于连接直接close即可不用考虑太多清理工作。重试策略上我不建议对每次失败都无脑重连三次。ECONNREFUSED时通常是服务端根本没监听重试间隔可以拉长比如1秒、5秒、30秒的退避。ETIMEDOUT时说明网络路径不通重试前先确认路由和防火墙别让客户端无限重试把日志刷爆。3.3 shutdown()与close()别让连接断得不明不白客户端主动断开连接时有人用close()有人用shutdown()踩坑的不少。close()只是在当前进程里减少引用计数如果这个套接字被其他线程或子进程共享连接不一定会真正关闭。shutdown()则是直接针对连接本身操作不关心引用计数。业务上常见场景是客户端发完请求不再写数据但仍想读服务端响应。这时应该shutdown(fd, SHUT_WR)这会让内核发送FIN语义是我说完了但还是会听你说。如果直接close()可能因为引用计数未归零服务端迟迟收不到FIN两边一起傻等。还有一个隐蔽的坑向一个对端已经关闭的连接继续write第一次可能成功第二次会触发SIGPIPE信号默认行为是终止进程。很多服务进程莫名其妙消失就是没处理SIGPIPE。处理方式是在程序初始化时忽略它signal(SIGPIPE, SIG_IGN);然后靠write返回EPIPE来感知连接已关闭。这是每一个写过TCP通信的人迟早会遇到的问题早点处理为妙。4. 从每连接一线程到epoll并发模型怎么选并发模型的选择决定了你的服务能在什么量级下稳住。我不会推荐最好的模型因为不存在。这里把主流方案放在一起对比说清楚适用边界。4.1 每连接一线程的代价一个连接2MB虚拟内存最简单的并发方式是accept后来一个客户端就创建一个线程。代码好写但经不起算账一个线程默认栈空间约8MB虚拟内存即使只用到几KB进程的虚拟内存空间也会被撑大。线上常见的现象是连接数几百时一切正常到两三千时突然OOM就是因为线程开销失控。线程池是对它的改进提前创建固定数量的工作线程每个线程循环accept或从队列取连接处理。好处是线程数可控坏处是一个慢客户端可能占住线程不放导致后面排队。服务端压力测试里最怕的就是个别客户端不读数据把线程池活活拖死。4.2 select模型的天花板FD_SETSIZE1024如果用select管理连接有个铁板一块的限制内核中的默认FD_SETSIZE是1024即select最多监视1024个文件描述符。你想监视更多还得重新编译内核或修改宏定义不现实。select另一个低效点是每次调用都要把所有fd从用户态拷贝到内核态内核遍历全部fd返回后再遍历一遍找出哪些就绪。连接数上千后这个复制的开销非常可观。所以select适合连接数少、逻辑简单的场景作为学习I/O多路复用的入门模型没问题但不建议作为高并发服务的底层。4.3 epoll的LT与ET边缘触发为什么容易丢事件epoll是在Linux 2.6引入的模型它只返回真正就绪的事件避免了反复遍历全部fd。但有两个触发模式水平触发LT和边缘触发ET。LT的意思是只要fd还有数据没读每次epoll_wait都会通知你。ET的意思是fd从无数据变成有数据的那一刻只通知一次之后就算你没读完它也不再触发新的事件除非又有新数据到达。ET模式效率更高但程序员必须一次把数据读干净否则就可能丢数据。比如一个fd收到100字节你只读了50字节之后没有新数据进来那个剩余50字节的读事件就不会再来了。这就是ET模式下最经典的坑。我给出的工程建议在没完全吃透ET语义之前用LT。性能差距在绝大多数业务下可以忽略但LT的容错性高得多。下面的示例是一个基于LT的epoll服务端骨架监听套接字和新连接都注册EPOLLIN事件int epfd epoll_create1(0); if (epfd 0) { perror(epoll_create1); return -1; } struct epoll_event ev, events[64]; ev.events EPOLLIN; ev.data.fd listen_fd; epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, ev); while (1) { int n epoll_wait(epfd, events, 64, -1); for (int i 0; i n; i) { int fd events[i].data.fd; if (fd listen_fd) { int conn_fd accept(listen_fd, NULL, NULL); if (conn_fd 0) continue; ev.events EPOLLIN; ev.data.fd conn_fd; epoll_ctl(epfd, EPOLL_CTL_ADD, conn_fd, ev); } else { handle_client(fd, epfd); } } }这里要注意一个细节监听fd在LT模式下只要有连接处于全连接队列里accept就会不停触发。如果accept后忘记设置新fd为非阻塞某个客户端恶意发送大量数据时你的服务可能被阻塞在这个连接的read上其他所有连接全部停摆。所以epoll模型下所有连接fd一律设置O_NONBLOCK这是铁律。5. 粘包与拆包TCP字节流和消息的边界五年前我第一次写TCP通信的时候特别困惑一个问题我明明send了两次数据对端recv却一次性收到了。当时以为是自己代码写错了后来才明白这就是TCP的流式特性它只保证字节流的顺序不保证消息边界。简单说把send的次数对应recv的次数这个直觉是错的。5.1 两次send一次recv流协议带来的错觉假设客户端连续发送两个消息A和B服务端可能recv到AB、A和B分两次、甚至A的一部分B的一部分拼起来——什么组合都可能出现。原因在于发送端内核的发送缓冲区、网络的分组、接收端内核的接收缓冲区每一层都可能把数据重新拼接。这就是常说的粘包和半包。粘包指多个消息在接收端粘在一起半包指一个消息被拆成了两半。这是TCP通信绕不开的基础问题应用层必须自己约定消息的边界。5.2 三种拆包方案对比方案原理优点缺点定长包每个消息固定长度实现简单解析快短消息浪费带宽长消息无法表达分隔符消息之间用特殊字符分隔适合文本协议消息内容不能包含分隔符需要转义长度头消息前加固定长度字段表示包体长度通用、灵活、支持二进制需要处理半包实现复杂度略高三种方案里长度头是生产环境最常用的很多知名协议如HTTP头部里的Content-Length、MQTT的固定头都属于这一类思路。定长包适合传输固定结构的数据比如传感器上报分隔符适合RTSP、FTP这类命令行式协议。选择标准要看你的消息是什么格式消息里可不可能出现分隔符对应的字节短消息占比有多大。5.3 手写一个带缓冲区的拆包读取循环用长度头拆包经典的做法是4字节网络字节序长度包体。因为read可能只读入部分数据必须写一个读满N字节的工具函数然后按协议逐步解析。下面是一个典型的readn函数ssize_t readn(int fd, void *buf, size_t n) { size_t left n; ssize_t r 0; char *p (char *)buf; while (left 0) { r read(fd, p, left); if (r 0) { if (errno EINTR) continue; return -1; } else if (r 0) { break; // 对端关闭返回已读字节数 } p r; left - r; } return n - left; }在这个基础上解析一个完整消息的逻辑就是先读4字节长度得到N再继续读N字节数据。但这还是简单场景。更工程化的做法是给每个连接维护一个应用层接收缓冲区把内核缓冲区读到的数据先放进自己的缓冲区再从缓冲区里尝试解析消息解析失败就先留着等后续数据到达再继续。缓冲区管理的核心是防止搬来搬去。网上的很多代码用memmove把剩余数据往前挪数据量大时会成为瓶颈。你可以用读索引和写索引两个指针管理缓冲区解析完一部分后更新索引定期把未消费数据搬到头部既保证不丢数据又能控制内存占用。6. 一次假死连接的线上排查全过程最后分享一次让我印象很深的线上排查。问题表象是客户端偶发超时服务端日志却一片安静没有错误没有崩溃。这种假死问题最容易让人挠头因为任何地方都没报错但连接就是不通了。6.1 现象客户端偶发超时服务端无异常日志当时有一个长连接网关连接池里维护着一批到后端服务的TCP连接。客户端每隔几秒发一次心跳正常情况下心跳响应很快。可某段时间客户端日志开始出现heartbeat timeout每次持续几十秒然后自己恢复。奇怪的是后端服务完全无感知进程在跑监控正常就像什么都没发生过。6.2 排查链路strace、ss、tcpdump逐层定位我习惯按应用层→内核层→网络层的顺序排查。先看应用层服务端日志没报错怀疑是卡在某个系统调用上于是用strace跟踪服务进程看它在故障时间内做了什么。strace的结果揭示了问题某个连接的recvfrom返回值为0即对端发来了EOF但服务端代码在处理这个EOF的路径上异常重试导致连接没有被及时关闭。更诡异的是这个连接在ss命令里仍然显示为ESTAB状态且收发队列都是0看起来既不像关掉了也不像有数据在传输。接着用tcpdump在服务端抓包。抓到的现象是服务端持续收到对端重传的TCP keepalive探测包但服务端不回ACK。对端等不到ACK以为连接还没断就一直重传。服务端这边的内核其实早就知道连接对端不可达但由于双方应用层都没检测到异常这条僵尸连接就一直挂在连接池里直到客户端整体重连才恢复。6.3 根因与修复TCP keepalive解决不了的场景根因有两点。第一服务端代码收到EOF后没有走正常的关闭流程而是错误地进入了重试循环导致应用层一直认为连接可用。第二底层TCP连接的假死状态靠默认的TCP keepalive根本发现不了——默认keepalive要等7200秒空闲才开始探测整套流程走完可能超过2分钟瞬间业务超时早就发生了。修复分三层做。首先是代码层面正确处理recv返回0的情况收到EOF就进入关闭流程不要做无意义重试。其次是内核参数层面在业务允许的前提下把tcp_keepalive_time调低到30秒tcp_keepalive_intvl调到5秒tcp_keepalive_probes保持默认9次让内核更早发现死连接。最后是应用层层面真正可靠的方案是添加应用层心跳。TCP keepalive只告诉你这条TCP路径通不通而应用层心跳能确认对方应用逻辑是否正常。常见做法是客户端周期性发Ping服务端回Pong并维护最近活跃时间超时未收到Pong就主动断开。有的协议把心跳和业务数据合并减少无意义的空包效果也很好。这次故障让我养成一个习惯所有长连接代码禁止只依赖TCP自身的保活机制所有对端关闭的分支必须显式处理并记录日志。日志里只要能看到connection closed by peer: fd7这类信息以后再出现类似假死问题定位速度会快很多。回头再看TCP通信这几件事边界其实很清晰连接怎么建、数据怎么传、连接怎么关每一环都有内核级的约束和应用层的对策。把这些基础吃透再上框架、再调优出问题时思路也就不会乱了。

相关新闻

顺序表与ArrayList:从手写实现到源码剖析与性能避坑

顺序表与ArrayList:从手写实现到源码剖析与性能避坑

如果你在大学修过《数据结构》这门课,或者正在准备考研、期末复习,又或者才学Java没多久就撞上了ArrayList,那么这篇内容你大概率能看下去。顺序表(SeqList)几乎是所有《数据结构》教材第一个认真讲透的线性结构&#…

2026/10/4 2:35:06 阅读更多 →
Conda虚拟环境中pip安装包路径错乱?一文厘清conda与pip的安装机制

Conda虚拟环境中pip安装包路径错乱?一文厘清conda与pip的安装机制

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

2026/10/4 2:34:06 阅读更多 →
2025技术年终总结:微服务架构升级、性能优化与稳定性实战

2025技术年终总结:微服务架构升级、性能优化与稳定性实战

1. 项目概述与年度定位1.1 核心需求解析2025年对全知科技来说,是一个从“能跑”到“跑得稳”的关键转折点。年初定调的时候,我们团队内部吵了好几轮,最后达成共识:这一年不追求新概念的数量,不搞花活,核心就…

2026/10/4 2:34:06 阅读更多 →

最新新闻

OpenNOW架构揭秘:Qt Quick + Rust双进程设计如何抛弃Electron重写GeForce NOW客户端

OpenNOW架构揭秘:Qt Quick + Rust双进程设计如何抛弃Electron重写GeForce NOW客户端

OpenNOW架构揭秘:Qt Quick Rust双进程设计如何抛弃Electron重写GeForce NOW客户端 【免费下载链接】OpenNOW Custom GeForce Now Client Named OpenNOW 项目地址: https://gitcode.com/gh_mirrors/op/OpenNOW OpenNOW 是一款开源的 GeForce NOW 桌面客户端&…

2026/10/4 3:04:22 阅读更多 →
JSP+SSM网上服装销售系统毕业设计:从环境配置到部署避坑全流程

JSP+SSM网上服装销售系统毕业设计:从环境配置到部署避坑全流程

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

2026/10/4 3:04:22 阅读更多 →
把截图直接拖进对话框:Agent Client for Obsidian如何向AI智能体发送图片与文件

把截图直接拖进对话框:Agent Client for Obsidian如何向AI智能体发送图片与文件

把截图直接拖进对话框:Agent Client for Obsidian如何向AI智能体发送图片与文件 【免费下载链接】obsidian-agent-client Bring AI agents into Obsidian via Agent Client Protocol (ACP), such as Claude Code, Codex and Gemini CLI. 项目地址: https://gitcod…

2026/10/4 3:04:22 阅读更多 →
如何一文看懂自主AI研究:awesome-autoresearch带你完整入门Karpathy autoresearch生态

如何一文看懂自主AI研究:awesome-autoresearch带你完整入门Karpathy autoresearch生态

如何一文看懂自主AI研究:awesome-autoresearch带你完整入门Karpathy autoresearch生态 【免费下载链接】awesome-autoresearch A curated list of autonomous improvement loops, research agents, and autoresearch-style systems inspired by Karpathys autoresea…

2026/10/4 3:04:22 阅读更多 →
OpenShell 使用指南:经典开始菜单回归与效率提升

OpenShell 使用指南:经典开始菜单回归与效率提升

1. 从零认识 OpenShell:它到底解决什么问题第一次听到 OpenShell 这个名字,很多人会下意识以为它是某个操作系统的内核项目,或者是一个新的命令行终端工具。实际上,OpenShell 是一个面向 Windows 平台的开始菜单替代与增强工具&am…

2026/10/4 3:04:22 阅读更多 →
SQL Server随机查询的几种写法与封装实践:从NEWID()到自定义函数

SQL Server随机查询的几种写法与封装实践:从NEWID()到自定义函数

搞随机查询这种需求,估计大多数SQL Server开发都写过。一句ORDER BY NEWID()下去,看似轻松搞定,真正上线后遇到大表慢、抽样不准、脚本重复维护这些问题,才是最磨人的。最近项目里有个抽奖节奏的需求,要从用户表里随机…

2026/10/4 3:03:22 阅读更多 →

日新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/4 1:00:58 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/4 1:00:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/2 10:36:31 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/3 9:42:35 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/3 9:42:36 阅读更多 →