多播与广播编程实战:从原理到代码排障

我最早接触多播和广播,是在调一个局域网内多台设备的同步程序时被逼出来的。当时用单播一条条发指令,设备一多,数据包就像早高峰的地铁,挤在一条链路上,延迟和丢包全都来了。后来换成广播,一台发、全网收,代码确实简单了,但马上又踩到广播风暴和跨网段不可达的坑。再后来才认真把多播协议啃了一遍,发现它才是真正的“中间路线”。这篇就把我在TCP/IP网络编程里折腾多播与广播的经验,从原理到代码到排障,完整梳理一遍。

1. 先搞明白:广播和多播到底解决什么问题

1.1 单播的瓶颈与广播的由来

正常情况下,两台主机通信就是单播:源IP发一个数据包,目的IP只有一个,中间交换机根据目的MAC精确转发,其他端口收不到,效率很高。但单播有个天生缺陷——如果你想给局域网内50台设备同时发同样的数据,就得把同样内容复制50份,逐个发送。这在设备少的时候无所谓,设备一多,不仅消耗发送端带宽,还会占用大量网络资源。

广播就是为了解决“一对多同时送达”而出现的。IPv4里,目的地址是255.255.255.255,或者带有子网广播地址,比如192.168.1.x网段的广播地址192.168.1.255。发送端只要往这个地址扔数据包,交换机就会把它转发到同一广播域内的所有端口,所有主机都会收到。它的优点是简单粗暴,缺点是“所有人被迫收听”——不管你是不是真需要这份数据,网卡都要把它收进来,交给上层协议判断处理。

1.2 广播的局限:不可跨网段、干扰严重

广播有一个硬性限制:路由器默认不转发广播包。也就是说,广播只能在同一个二层广播域内生效,出了子网就没了。这在早期的局域网应用里问题不大,但一旦网络规模变大、划分了VLAN,广播包就跨不过去。

还有一个问题就是干扰。我见过一些简陋的程序,把心跳包、状态同步、文件分片全用广播实现,结果整个局域网都被无关流量淹没,其他业务卡到没法用。你发送广播包时,同一广播域内所有主机的CPU都会被中断唤醒一次,哪怕这些主机根本不需要你的数据。轻则网络拥塞,重则形成广播风暴,直接把交换机打垮。

1.3 多播是“按需订阅”的折中方案

多播(组播)走的路子不同。它引入了一个“组”的概念:发送方往一个组地址发数据,只有加入这个组的主机才会收到。具体来说,IPv4多播地址范围是224.0.0.0到239.255.255.255,属于D类地址。发送方把数据发到某个组地址,网络设备会根据组管理协议,把数据复制给所有“订阅”了该组的主机。

你可以把多播想象成电台广播:电台往一个频段发信号,只有把收音机调到那个频段的用户才能听到,其他拿着收音机却没调台的人完全不受打扰。而在电脑网络里,“调台”这个动作就是IGMP(Internet Group Management Protocol)——主机用它向路由器声明“我要听这个组的节目了”。

多播的好处是跨网段可行。只要沿途路由器都启用了多播路由协议(比如PIM),组播数据就能从源端一路送到各个子网,每个子网上有接收者的地方才会复制副本。这对视频会议、行情分发、在线直播这类“一对多、接收者分布在不同网段”的场景来说,几乎是最优解。

2. 广播编程实战:从socket到收发的完整细节

2.1 广播发送端的关键步骤

广播编程和普通UDP编程非常像,唯一多出来的关键步骤就是设置SO_BROADCAST选项。不设置这个选项,你往广播地址sendto,系统会直接返回错误,比如errno为EACCES(权限不足),这其实是操作系统的一层保护机制,防止应用程序无意识地乱发广播包。

发送端伪代码大致如下:

int fd = socket(AF_INET, SOCK_DGRAM, 0); int broadcast = 1; setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)); struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(6000); addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); // 255.255.255.255 char msg[] = "hello everyone"; sendto(fd, msg, strlen(msg), 0, (struct sockaddr *)&addr, sizeof(addr));

这里有个容易迷糊的点:INADDR_BROADCAST是255.255.255.255,也就是受限广播地址。这个地址只能在当前子网内广播,不会跨网段。如果你想对特定子网广播,就要填成那个子网的定向广播地址,比如192.168.1.255,前提是发送端自己也在这个子网里,否则会被路由器丢弃。

2.2 接收端的绑定策略与常见歧义

接收广播的socket必须绑定到某个端口,才能收到数据。但绑定地址有讲究:

  • 绑定INADDR_ANY(0.0.0.0),可以收到发往本机任意IP地址的广播包。
  • 绑定具体的IP地址,比如192.168.1.100,就只能收到发往这个IP地址的广播包。

很多新手在接收端用recvfrom时,明明收到了数据,却不知道对方到底是谁发来的。这里要注意:recvfrom返回的sockaddr_in里存的是发送端的IP和端口,你可以用它做来源判断或者回复。

还有一个坑是端口复用。如果同一台机器上两个进程都绑定了同一个UDP端口,默认情况下后一个进程会绑定失败,因为端口冲突。但在广播场景下,有时我们希望多个进程都能收到同一个广播包,这时需要设置SO_REUSEADDR,并且所有进程绑定同一个端口。不同操作系统对这种“多个socket绑定同一端口”的支持程度不一样,Linux下通常只要都设置了SO_REUSEADDR就能共存,但Windows下的行为略有差异,建议实际测试。

2.3 广播包能带多少数据?MTU的影响

UDP广播包的数据长度并不是“想发多少就发多少”。受底层MTU(最大传输单元,常见以太网为1500字节)限制,UDP数据报超过一定长度就必须分片。对IPv4来说,UDP头部8字节 + IP头部20字节,留给应用层的最大理论长度是65507字节,但这个长度一旦超过网络MTU,就会触发IP分片——多个分片在接收端重新组装,而且只要丢一个分片,整个数据报就废了。

实践里,局域网内广播包我一般控制在1400字节以内,避开MTU边界,既不用分片也不怕丢包。如果非要传大块数据,比如文件分发,就不建议用UDP广播了,要么自己实现可靠重传,要么换TCP单播配合P2P分发,否则调试分片重组问题会让人怀疑人生。

3. 多播编程实战:组管理、TTL与跨网段细节

3.1 加入多播组:setsockopt的隐藏逻辑

多播编程的核心动作是“加入组”。发送端和接收端都可以加入/离开组,但真正的接收者必须加入组,才能收到发往该组的数据。

加入组的代码常见写法:

struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = inet_addr("239.0.0.10"); mreq.imr_interface.s_addr = htonl(INADDR_ANY); // 使用默认网卡 setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

这段代码最关键的是imr_interface。它指定了要从哪个网卡接口加入多播组。如果你的机器只有一块网卡,填INADDR_ANY没问题;但如果有多块网卡(比如有线和无线同时连接),默认接口不一定是你要的那块,收到的数据可能完全不对。我遇到过一例,笔记本上无线网卡连了公司Wi-Fi,有线网卡连了一台测试交换机,结果多播数据老是收不到,折腾半天发现是系统默认走了无线接口。后来改成显式指定有线网卡的IP地址,问题立刻解决。

所以生产环境里,我强烈建议imr_interface不要填INADDR_ANY,而是明确指定具体网卡IP。比如:

inet_pton(AF_INET, "192.168.5.20", &mreq.imr_interface);

这样才能掌控数据从哪张网卡进、哪张网卡出。

3.2 设置TTL:控制多播包的生命半径

多播包的TTL(Time To Live)非常关键。在IP头部,TTL每经过一个路由器就减1,减到0就丢弃。多播场景里,TTL不仅代表剩余跳数,还经常被用来限制分发范围。

  • TTL=1:多播包只能停留在本地子网,不会被路由器转发。
  • TTL=2~...:每大于1,就允许跨过一个路由器。

我在做局域网多播同步时会设置TTL为1,避免数据跑到上层网络造成不必要的麻烦。做跨网段业务时会设成4或8,但要配合路由器上的多播路由配置。

设置方法:

unsigned char ttl = 1; setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));

注意这里TTL类型是unsigned char(1字节),不是int,很多人在这上面吃过亏,设置成int类型的4字节值,结果协议栈只取低八位,行为很怪异。

3.3 发送者的源地址选择与多网卡问题

多播发送端还有个容易踩的坑:socket默认往外发包时,源IP地址由操作系统根据路由表选,这个源IP有可能不是多播组所在网卡的那个IP。最简单粗暴的办法是绑定本地地址:

struct sockaddr_in local; local.sin_family = AF_INET; local.sin_port = htons(0); // 随机端口 local.sin_addr.s_addr = htonl(INADDR_ANY); bind(fd, (struct sockaddr *)&local, sizeof(local)); unsigned char loop = 1; setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &local.sin_addr, sizeof(local.sin_addr));

IP_MULTICAST_IF可以指定多播包从哪张网卡发出去。同时还可以设置IP_MULTICAST_LOOP,控制“本机自己是否也能收到自己发的多播包”。如果设为0,本机发送的多播数据不会回环给本机socket,这在某些测试场景下容易误以为没发出去,实际别的机器收到了。

3.4 多播收发完整示例

下面是我在实际项目中用过的一个最小多播通信骨架,发送端向239.0.0.10端口8000发数据,接收端加入该组并监听。

发送端核心代码:

int fd = socket(AF_INET, SOCK_DGRAM, 0); unsigned char ttl = 4; setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); struct sockaddr_in group; group.sin_family = AF_INET; group.sin_port = htons(8000); inet_pton(AF_INET, "239.0.0.10", &group.sin_addr); char buf[1024]; while (1) { fgets(buf, sizeof(buf), stdin); sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&group, sizeof(group)); }

接收端核心代码:

int fd = socket(AF_INET, SOCK_DGRAM, 0); int reuse = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); struct sockaddr_in local; local.sin_family = AF_INET; local.sin_port = htons(8000); local.sin_addr.s_addr = htonl(INADDR_ANY); bind(fd, (struct sockaddr *)&local, sizeof(local)); struct ip_mreq mreq; inet_pton(AF_INET, "239.0.0.10", &mreq.imr_multiaddr); mreq.imr_interface.s_addr = htonl(INADDR_ANY); setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); char buf[1024]; struct sockaddr_in peer; socklen_t len = sizeof(peer); while (1) { int n = recvfrom(fd, buf, sizeof(buf) - 1, 0, (struct sockaddr *)&peer, &len); if (n > 0) { buf[n] = '\0'; printf("receive from %s: %s\n", inet_ntoa(peer.sin_addr), buf); } }

这个例子没有处理差错重传,适合对丢包不敏感的场景。如果业务要求可靠性,多播之上还需要自己加序列号、ACK、重传等机制。

3.5 多播地址怎么选:避开预留段与冲突

多播地址看上去随便挑,但实际有讲究。标准里224.0.0.0到224.0.0.255这一小段是局域网保留地址,比如224.0.0.1是所有主机、224.0.0.2是所有路由器,这些地址不能被应用程序随意占用。另外,239.0.0.0到239.255.255.255是本地管理范围(administratively scoped),类似我们常说的私网IP,适合在组织内部使用,不会被公网路由。所以我做内部多播业务时,一般都从239.x.x.x里挑,减少冲突风险。

但要注意,不同业务如果用了同一个239地址,又没有被VLAN隔离,数据就会串台。我习惯在项目里专门维护一张“多播地址分配表”,哪个服务用哪个组、哪个端口,都提前规划好,不然上线后想查是谁在发数据,抓包抓得头大。

3.6 多播与广播收发的关键区别

用表格对比一下多播和广播:

对比项广播多播
目的地址255.255.255.255 或子网定向广播地址224.0.0.0 ~ 239.255.255.255
是否跨网段路由器通常不转发路由器可转发(需配置多播路由)
对无关主机影响所有主机都会接收仅加入组的主机接收
是否需要额外配置仅需SO_BROADCAST,简单需要加入组,可设置TTL、接口等
与IGMP的关系不需要需要IGMP报告
典型场景局域网自动发现、ARP前的小范围通知流媒体、行情分发、集群同步、跨网段订阅

4. 实务经验:常见问题、排障技巧与协议优化方向

4.1 现象一:广播包发出去,接收端就是收不到

这种事十有八九是防火墙或交换机隔离问题。先看防火墙:Linux的iptables/nftables可能在filter表里默认丢弃了广播或多播包,尤其是开启了“仅允许本机IP”这类策略时,广播地址会被过滤。Windows的防火墙默认也会拦截传入的UDP广播,需要手动允许应用或开放端口。

再看交换机:如果交换机端口开了“端口隔离”或“风暴控制”,广播包会被交换机直接丢弃。有些安全设备甚至会把广播包当成攻击流量阻断。排查时先用抓包工具(比如tcpdump或Wireshark)在发送端和接收端分别抓包,确认包是“没发出来”“出网卡被丢”还是“到达接收端后被应用层忽略”。我常用的三步:

  1. 在发送端tcpdump -i eth0 udp port 6000,看包是否从网卡出去。
  2. 在接收端tcpdump -i eth0 udp port 6000,看包是否到达网卡。
  3. 如果到达网卡但应用收不到,检查防火墙和socket绑定地址、端口。

4.2 现象二:多播跨网段失败

多播跨网段不是“配置了IP_ADD_MEMBERSHIP就完事”,还依赖网络设备层。路由器上必须启用多播路由协议,比如PIM稀疏模式或密集模式,并且要处理IGMP侦听。如果中间路由器没有运行PIM,多播包就会被静默丢弃——你抓包看到源端出了网卡,但目的端网卡上连影子都没有。

还有一种情况是交换机开启了IGMP Snooping,但配置不当,导致多播流量只发给某些特定端口,其他端口收不到。遇到这种问题,先确认目的设备所接的交换机端口是否属于多播组对应的VLAN,再检查IGMP Snooping表的条目是否正确。把交换机上IGMP Snooping临时关掉,看看能不能恢复,只要恢复了,问题就锁定在Snooping配置上。

4.3 现象三:多个接收进程收到同一个多播包

这是预期行为,不算故障。多播本就是“加入组的所有socket都收到”,如果同一台机器上多个进程绑定了同一端口且都加入了组,它们确实都能收到同一份数据。有些业务会故意这么设计来做负载均衡或者主备热备:备用进程收包但不处理,主进程故障后立即接管。但也因此带来一个坑:TCP端口冲突问题在UDP多播里几乎不存在,因为你必须依赖SO_REUSEADDR去允许多进程共用端口,忘了设置就会绑定失败。

4.4 抓包工具与命令速查

排查UDP广播或多播问题时,我习惯用以下命令快速定位:

# 查看机器已加入的多播组 cat /proc/net/igmp # 发送广播测试,每次发一行 echo "hello" | nc -u -b 255.255.255.255 6000 # 加入多播组(Linux可用ip命令添加静态组) ip maddr add 239.0.0.10 dev eth0 # 抓多播包,只看指定组和端口 tcpdump -i eth0 -nn 'ip dst 239.0.0.10 and udp port 8000' # 查看路由表里多播路由条目 ip route show table multicast

/proc/net/igmp很有用,如果应用已经调用了IP_ADD_MEMBERSHIP,但这里看不到对应组,说明socket可能没绑定成功,或者程序运行的namespace和抓包的namespace不一致。另外,用ip maddr add添加的静态组是网络层级别的,与socket无关,适合测试用,但生产环境不推荐。

4.5 编程层面的避坑建议

  • 检查每个socket调用的返回值。setsockopt(IP_ADD_MEMBERSHIP)在网卡接口名不对、或者该接口不支持多播时,会返回错误。很多教程贴代码不检查返回值,导致“代码能编译、运行没报错、但功能不正常”的现象。
  • UDP是面向数据报的,收发都有边界。发送端一次sendto对应的就是一个完整的recvfrom数据报,如果接收方buffer太小,数据会被截断,多余部分直接丢弃。所以接收buffer尽量开大点,2KB起步,必要时用setsockopt调整SO_RCVBUF。
  • 多播接收端一般也要设置SO_REUSEADDR,原因和多个进程绑同一个端口有关,另外在BCast测试时还能避免TIME_WAIT之类的干扰。
  • 注意字节序。多播地址如果用字符串形式(“239.0.0.10”)还好,如果自己拼struct in_addr要搞清楚host order和network order,别把四个字节搞反了。

4.6 从广播平滑演进到多播的迁移思路

如果你现在还有一套跑在广播上的老系统,想改成多播又不希望大动干戈,我建议分两步走:

第一步,把“发现服务”和“业务数据传输”分开。服务发现可以用广播,这样新设备接入后能立刻感知;业务数据改为多播,避免所有主机都被无关流量干扰。这样改动量小,价值直接。

第二步,逐步把所有广播发包替换成多播地址。发送端把目的地址从255.255.255.255改成239.0.0.0段的地址,接收端加入对应的多播组。这一步改起来非常快,关键是要规划好组地址和端口,并确认交换机/路由器的IGMP Snooping配置跟得上。

我见过最糟糕的迁移方式,是直接在生产环境把所有广播改成多播,但没检查网络设备是否支持IGMP Snooping,结果某些主机完全收不到包,业务直接中断。所以迁移前务必先在小范围VLAN里做充分验证。

多播和广播表面上只是“换个目的地址”,实际背后的网络行为完全不同。广播是“强制全员参与”,多播是“按需订阅”。做网络编程的人如果没搞清楚这两者本质,很容易写出能跑但一上规模就出问题的代码。我个人经验是:小范围、低频率的通知用广播,省事;大范围、高频次的批量发送用多播,省带宽、不扰民。

最后再分享一个小技巧:写多播代码时,先把TTL设为1,在单机回环上测通,再用两块网卡物理直连测,最后才上交换机。这个逐步扩大范围的思路能帮你把“代码问题”和“网络问题”分离开,排查效率会高很多。

相关新闻

AI芯片选型指南:从TOPS参数到功耗生态的实用过滤方法

AI芯片选型指南:从TOPS参数到功耗生态的实用过滤方法

年初有位朋友做边缘计算设备选型,一开始列了个 AI 芯片候选清单,拢共 57 款,觉得已经覆盖得很全面了。结果调研越做越深,发现同一个厂家在不同产品线、不同代际、甚至不同封装下都会分出好几款,最后这份清单硬生生整理…

2026/10/20 14:19:18 阅读更多 →
多模态数据扩散模型做预测:原理、实操与工程落地全解析

多模态数据扩散模型做预测:原理、实操与工程落地全解析

打开扩散模型相关论文的时候,我第一反应也是“又一个做图像生成的”。直到我自己把扩散模型接到一个多模态预测项目上,才发现这条路的价值被严重低估了。传统的预测模型,不管是LSTM、Transformer还是各种树模型,本质上都在学“给定…

2026/10/20 14:18:12 阅读更多 →
AA-Scan:可编程扫描仪行为建模工具

AA-Scan:可编程扫描仪行为建模工具

简介:AA-Scan是一款基于Arduino与Android平台的开源全自动3D扫描仪软硬件方案,面向嵌入式开发初学者、创客及三维建模爱好者,解决低成本、易组装、可复现的简易3D扫描设备搭建问题。资源包为完整项目源码,共5个文件:含…

2026/10/20 14:18:12 阅读更多 →

最新新闻

5分钟粒度时间序列预测:ARIMA全流程实战与坑点解析

5分钟粒度时间序列预测:ARIMA全流程实战与坑点解析

数据准备:5分钟数据的“脏活累活” 2.1 采集与落库,先解决有没有的问题 2.2 缺失值处理,别让“空洞”骗了模型 2.3 异常值甄别,业务噪声与真实波动的边界 2.4 重采样与对齐,把时间轴捋直了 数据是一切时序建模的地…

2026/10/20 16:43:46 阅读更多 →
降AIGC软件横评:9类工具原理、避坑与实操流程

降AIGC软件横评:9类工具原理、避坑与实操流程

最近这段时间,被问得最多的问题就是“到底有没有靠谱的降AIGC软件”。经常是头像一换,那边甩过一张截图,问“这种标红要怎么办”。尤其专科生群体,课程报告、实训总结、毕业设计说明一摊开,全是AI生成常见句式&#xf…

2026/10/20 16:43:46 阅读更多 →
Apache Pulsar 2.9.1 部署实战:从解压到集群调优的完整指南

Apache Pulsar 2.9.1 部署实战:从解压到集群调优的完整指南

简介:Apache Pulsar 2.9.1 的二进制发行包,面向需要搭建高吞吐消息队列与实时流处理管道的后端开发、架构师和云原生运维人员,解决分布式消息中间件选型与自建集群时的环境前置问题。压缩包约 321.53MB,为 tar.gz 格式&#xff0c…

2026/10/20 16:43:46 阅读更多 →
AI Agent任务规划、状态管理与长任务恢复:从原理到最小实现

AI Agent任务规划、状态管理与长任务恢复:从原理到最小实现

1. 从“能聊天”到“能干活”:任务规划到底在解决什么问题 很多人第一次接触 AI Agent,脑子里想的还是“更聪明的聊天机器人”。但真正做过 Agent 项目的人都知道,聊天只是最表层的能力,真正决定一个 Agent 能不能落地干活的&…

2026/10/20 16:43:46 阅读更多 →
Python AI编程入门指南:机器学习、深度学习、NLP与强化学习实战

Python AI编程入门指南:机器学习、深度学习、NLP与强化学习实战

1. 从零到一:为什么我建议你用Python切入AI编程很多人第一次接触AI编程,脑子里冒出来的第一个问题不是“怎么学”,而是“从哪开始”。我见过太多人抱着厚厚的数学书啃了三个月,结果连一行能跑的代码都没写出来,最后热情…

2026/10/20 16:43:46 阅读更多 →
医学图像处理代码实战:从DICOM读取到三维重建与分割

医学图像处理代码实战:从DICOM读取到三维重建与分割

前一阵有个刚转行做医学影像算法的朋友来找我,说他从某医院那边拿到了一批脱敏后的CT数据,文件夹里装着一堆后缀为 .dcm 的文件。他第一反应是像处理普通照片一样用 OpenCV 直接读,结果 cv2.imread 返回一大片乱码。这个场景我太熟悉了&#…

2026/10/20 16:42:44 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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/20 10:02:08 阅读更多 →
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/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练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/20 9:50:45 阅读更多 →