Java UDP网络编程实战:从原理到C/S通信案例
1. 为什么我选择用UDP做这个C/S通信案例1.1 从一次局域网调试说起前阵子帮一个做物联网设备的朋友排查问题他的设备端每隔一秒往服务器发一次状态心跳用的是TCP长连接。设备数量一上来服务器端就出现大量连接堆积资源占用高得离谱。我看了下场景心跳包很小丢一两个也无所谓下一包马上就到根本不需要TCP那种必须送达、顺序保证的重型机制。当时我就建议他把心跳通道换成UDP改完之后服务器负载直接降了一个数量级。这件事让我意识到很多做Java网络编程的朋友一提到Socket就默认上TCP对UDP的印象停留在不可靠、会丢包、不能用这种模糊认知上。其实UDP在实时性要求高、能容忍少量丢包、或者需要一对多广播的场景里反而是更合适的选择。所以我打算用一个完整的Java C/S通信案例把UDP这套东西从头到尾讲透包括协议原理、Socket API怎么用、代码怎么写、坑在哪里。这个案例适合谁看如果你已经会写基本的Java程序懂一点多线程想搞清楚网络编程里UDP这条线到底怎么落地那这篇内容就是给你准备的。我会从最基础的数据报概念讲起一路写到能跑起来的客户端和服务端中间穿插我自己踩过的坑和调试技巧。看完你至少能做到独立写出一个UDP的C/S通信程序知道什么时候该用它、什么时候不该用遇到问题知道往哪个方向排查。1.2 UDP和TCP到底差在哪别再用错场景要理解UDP编程先得把UDP和TCP的本质区别搞清楚。我用一个生活化的类比TCP像是打电话你得先拨号、对方接听、确认双方都在线然后才能说话说的每句话对方都会嗯一声确认收到顺序也不会乱UDP像是寄明信片你写好地址直接扔进邮筒不确认对方收没收到也不保证几张明信片按顺序到达甚至可能丢几张。这个差异落到技术层面核心是这么几点对比维度TCPUDP连接方式面向连接三次握手无连接直接发可靠性保证送达、去重、按序不保证可能丢、可能乱序传输效率头部开销大有拥塞控制头部仅8字节无拥塞控制传输方式字节流数据报一个个独立包适用场景文件传输、网页、登录实时音视频、心跳、广播、游戏关键要理解数据报这个概念。TCP是字节流你发100字节、再发200字节接收端可能一次读到300字节边界是模糊的。UDP不一样你发一个100字节的包接收端要么完整收到这100字节要么什么都没收到绝不会出现收到一半或者两个包粘在一起的情况。这个特性叫消息边界保留是UDP编程里非常重要的一个点后面写代码时会反复用到。那什么时候该用UDP我的经验判断标准是三条第一能容忍丢包比如实时语音丢一帧就丢一帧重传反而造成延迟第二需要低延迟比如游戏里的位置同步等TCP重传的功夫玩家早跑远了第三需要一对多比如局域网设备发现、服务广播。反过来凡是涉及钱、涉及数据完整性、涉及顺序的老老实实上TCP别为了省事用UDP给自己挖坑。1.3 这个案例的整体设计思路我设计的这个C/S通信案例目标很明确客户端发送消息服务端接收并回复双方能持续对话。为了把UDP的特性体现出来我做了几个设计决策。第一服务端用单线程循环接收。UDP是无连接的服务端不需要为每个客户端维护连接一个DatagramSocket就能接收所有客户端发来的包通过包里的来源地址区分是谁发的。这跟TCP服务端要为每个连接开一个线程完全不同资源占用低得多。第二客户端和服务端都用DatagramPacket来封装数据。这是UDP编程的核心类发送时把数据、目标地址、目标端口打包进去接收时用一个空包去接接完从包里取出数据和来源信息。第三我加了一个简单的应用层确认机制。UDP本身不保证送达但业务上如果确实需要知道对方收没收到可以在应用层自己实现一个收到请回复的逻辑。这个案例里我会演示怎么加但也会说明什么时候不该加。第四端口和地址都做成可配置的。实际项目里硬编码IP和端口是大忌我把它抽成常量或者参数方便你改。整个案例的代码量不大但麻雀虽小五脏俱全把UDP编程的发送、接收、地址解析、异常处理、资源释放这些环节都覆盖到了。下面我分模块拆开讲。2. 核心API拆解与实操前的准备2.1 DatagramSocket和DatagramPacket这两个类必须吃透Java的UDP编程核心就两个类DatagramSocket和DatagramPacket。把这两个类搞明白UDP编程就掌握了一大半。DatagramSocket可以理解成邮局它负责收发数据报。它有两个关键构造方法new DatagramSocket()会绑定一个随机可用端口通常客户端用这个new DatagramSocket(int port)会绑定指定端口服务端用这个因为客户端得知道往哪个端口发。这个类提供了两个核心方法send(DatagramPacket)发送receive(DatagramPacket)接收。注意receive是阻塞的没收到包就一直卡在那里这一点跟TCP的accept类似。DatagramPacket可以理解成信封它封装了数据内容、数据长度、目标地址、目标端口。发送用的包和接收用的包构造方式不一样这是新手最容易搞混的地方。发送用的包构造时要指定发给谁// 数据、数据长度、目标IP、目标端口 byte[] data hello.getBytes(); InetAddress target InetAddress.getByName(127.0.0.1); DatagramPacket sendPacket new DatagramPacket(data, data.length, target, 8888);接收用的包构造时只指定缓冲区多大不指定来源因为来源是收到之后才知道的byte[] buffer new byte[1024]; DatagramPacket receivePacket new DatagramPacket(buffer, buffer.length); socket.receive(receivePacket); // 收到后receivePacket里就有了来源地址和数据收到之后通过receivePacket.getAddress()拿来源IPgetPort()拿来源端口getData()拿数据getLength()拿实际数据长度。这里有个坑getData()返回的是整个缓冲区不是实际收到的数据。如果你缓冲区开了1024字节实际只收到10字节getData()还是返回1024字节的数组后面全是0。所以一定要用getLength()来截取有效数据这个坑我后面会专门讲。2.2 环境准备和项目结构环境这块没什么特殊要求JDK 8以上就行我用的是JDK 17语法上没用到太新的特性向下兼容。开发工具随意IDEA、Eclipse、VS Code都能写。不需要任何第三方依赖纯JDK自带的java.net包就够。项目结构我建议这样组织清晰好维护udp-demo/ ├── src/ │ ├── UdpServer.java // 服务端 │ ├── UdpClient.java // 客户端 │ └── UdpConstants.java // 常量配置UdpConstants.java放公共配置避免IP端口散落在各处public class UdpConstants { public static final int SERVER_PORT 8888; public static final String SERVER_HOST 127.0.0.1; public static final int BUFFER_SIZE 1024; public static final String CHARSET UTF-8; }这里我特意把字符集抽出来。UDP传输的是字节字符串转字节、字节转字符串都要指定字符集不指定就用平台默认跨平台时中文会乱码。统一用UTF-8是最稳的做法这个细节很多人会忽略等到线上出现乱码才回头找。提示缓冲区大小BUFFER_SIZE设多大合适UDP单个数据报理论上最大能到64KB左右受IP层限制但实际网络环境中超过MTU通常1500字节的包会被分片分片后任何一片丢了整个包就废了。所以业务上单个UDP包建议控制在1400字节以内缓冲区开1024或2048都行别开太大浪费内存。2.3 端口选择与防火墙注意事项端口选择有个经验1024以下的端口是系统保留端口需要管理员权限才能绑定普通程序别去碰。1024到49151是注册端口一般应用用这个范围。49152以上是动态端口系统临时分配用。我选8888属于注册端口好记又不容易冲突。实际部署时防火墙是UDP编程绕不开的坎。TCP有连接状态防火墙容易判断UDP无连接很多防火墙默认策略是只允许内部发出去的UDP回包不允许外部主动发进来的UDP包。所以如果你在云服务器上跑UDP服务端客户端连不上第一件事就是检查安全组和防火墙有没有放行UDP端口。这个坑我踩过不止一次本地测试好好的一上服务器就收不到包排查半天发现是防火墙。另外提一句127.0.0.1是回环地址只能本机通信。要让局域网其他机器连上服务端绑定时要用0.0.0.0或者不指定地址默认绑所有网卡客户端则要填服务端的真实局域网IP。这个区别新手经常搞混本地测试用127.0.0.1没问题一换机器就连不上。3. 服务端与客户端的完整实现3.1 服务端一个循环搞定收发服务端的逻辑很直白绑定端口开一个缓冲区循环接收收到就处理处理完回复。我先把完整代码贴出来然后逐段讲。import java.net.*; import java.nio.charset.StandardCharsets; public class UdpServer { public static void main(String[] args) { DatagramSocket socket null; try { // 1. 绑定端口服务端必须指定端口 socket new DatagramSocket(UdpConstants.SERVER_PORT); System.out.println(服务端已启动监听端口 UdpConstants.SERVER_PORT); byte[] buffer new byte[UdpConstants.BUFFER_SIZE]; // 2. 循环接收 while (true) { // 每次接收都要新建一个包避免复用导致数据错乱 DatagramPacket receivePacket new DatagramPacket(buffer, buffer.length); socket.receive(receivePacket); // 阻塞等待 // 3. 解析数据注意用 getLength() 截取有效长度 String msg new String( receivePacket.getData(), 0, receivePacket.getLength(), StandardCharsets.UTF_8 ); InetAddress clientAddr receivePacket.getAddress(); int clientPort receivePacket.getPort(); System.out.printf(收到来自 %s:%d 的消息%s%n, clientAddr.getHostAddress(), clientPort, msg); // 4. 构造回复 String reply 服务端已收到 msg; byte[] replyBytes reply.getBytes(StandardCharsets.UTF_8); DatagramPacket sendPacket new DatagramPacket( replyBytes, replyBytes.length, clientAddr, clientPort ); socket.send(sendPacket); } } catch (Exception e) { e.printStackTrace(); } finally { // 5. 释放资源 if (socket ! null !socket.isClosed()) { socket.close(); } } } }逐段说下关键点。第一步绑定端口new DatagramSocket(8888)如果端口被占用会抛BindException这个异常要能识别通常意味着有另一个程序占着这个端口换个端口或者杀掉占用进程。第二步循环接收这里有个细节DatagramPacket我放在循环体内每次新建。为什么因为receive方法会修改传入的包对象把来源地址、实际长度等信息写进去。如果你在循环外建一个包反复用虽然大多数情况也能跑但一旦出现异常或者数据长度变化容易出诡异问题。每次新建是最稳妥的代价就是一点对象创建开销对UDP这种场景完全可以接受。第三步解析数据重点看new String(data, 0, length, charset)这三个参数。第一个是缓冲区第二个是起始偏移0第三个是getLength()第四个是字符集。为什么不用new String(data, charset)因为那样会把整个缓冲区都转成字符串包括后面没用的0字节结果就是字符串末尾一堆乱码。这个坑非常经典我第一次写UDP就栽在这里收到的消息后面总是跟着一串问号。第四步回复用收到的来源地址和端口构造发送包原路返回。注意这里clientAddr和clientPort是从接收包里取的不是写死的这样服务端才能同时服务多个客户端。第五步资源释放放在finally里保证异常时也能关闭。DatagramSocket不关的话端口会一直被占用下次启动就报BindException。3.2 客户端发送、接收、再发送客户端比服务端稍微绕一点因为它既要发也要收而且收的时候也是阻塞的。我设计成发一条、收一条的问答模式逻辑清晰。import java.net.*; import java.nio.charset.StandardCharsets; import java.util.Scanner; public class UdpClient { public static void main(String[] args) { DatagramSocket socket null; try { // 1. 客户端不指定端口系统随机分配 socket new DatagramSocket(); // 2. 设置接收超时避免服务端没响应时永久阻塞 socket.setSoTimeout(5000); InetAddress serverAddr InetAddress.getByName(UdpConstants.SERVER_HOST); Scanner scanner new Scanner(System.in); System.out.println(客户端已启动输入消息发送输入 exit 退出); while (true) { System.out.print( ); String input scanner.nextLine(); if (exit.equalsIgnoreCase(input)) { break; } // 3. 发送 byte[] sendBytes input.getBytes(StandardCharsets.UTF_8); DatagramPacket sendPacket new DatagramPacket( sendBytes, sendBytes.length, serverAddr, UdpConstants.SERVER_PORT ); socket.send(sendPacket); // 4. 接收回复 byte[] buffer new byte[UdpConstants.BUFFER_SIZE]; DatagramPacket receivePacket new DatagramPacket(buffer, buffer.length); try { socket.receive(receivePacket); String reply new String( receivePacket.getData(), 0, receivePacket.getLength(), StandardCharsets.UTF_8 ); System.out.println(服务端回复 reply); } catch (SocketTimeoutException e) { System.out.println(等待服务端响应超时请检查服务端是否启动); } } } catch (Exception e) { e.printStackTrace(); } finally { if (socket ! null !socket.isClosed()) { socket.close(); } } } }客户端第一个关键点是new DatagramSocket()不指定端口让系统随机分配一个。因为客户端不需要被别人主动连接端口是多少无所谓系统分配就行。第二个关键点是setSoTimeout(5000)。UDP不可靠服务端可能没启动、可能挂了、可能包丢了如果不设超时receive会一直阻塞程序看起来像卡死。设了5秒超时后超时会抛SocketTimeoutException我们捕获它给用户一个友好提示。这个设置在实际项目里几乎是必须的我强烈建议你养成习惯。第三个关键点是发送和接收的包分别构造。发送包指定目标地址端口接收包只指定缓冲区。这里我在循环内每次新建缓冲区避免上一轮的数据残留影响下一轮。3.3 跑起来看看效果代码写完先启动服务端再启动客户端。服务端控制台输出服务端已启动监听端口8888客户端输入你好服务端立刻打印收到来自 127.0.0.1:54321 的消息你好客户端收到回复服务端回复服务端已收到你好注意客户端端口54321是系统随机分配的每次启动可能不一样这就是UDP无连接的体现——服务端不关心你是谁只根据包里的来源地址回给你。你可以同时启动多个客户端服务端都能处理因为它是单线程循环来一个包处理一个。这就是UDP服务端资源占用低的原因不需要为每个客户端维护连接状态。3.4 参数计算缓冲区到底开多大前面提了缓冲区大小这里展开算一下。UDP数据报的结构是IP头20字节 UDP头8字节 数据。以太网MTU是1500字节所以UDP数据部分最大约1472字节1500 - 20 - 8。超过这个值IP层会分片分片增加丢包风险。所以我的建议是业务上单个UDP包控制在1400字节以内缓冲区开1024或2048。如果你要传大文件别用UDP硬扛要么自己在上层做分片重组要么直接换TCP。我见过有人用UDP传几MB的文件自己写分片和重传最后代码复杂度比直接用TCP高十倍得不偿失。字符编码也要算进去。UTF-8下一个中文占3字节一个英文占1字节。如果你缓冲区开1024理论上能放341个中文。但实际业务里还要留余量别卡着边界用。4. 常见问题与排查技巧实录4.1 收到乱码怎么办乱码是UDP编程最高频的问题没有之一。原因通常有三个发送端和接收端字符集不一致、接收时没截取有效长度、缓冲区复用了脏数据。第一个原因最好排查两端都统一用StandardCharsets.UTF_8别用new String(bytes)这种依赖平台默认字符集的写法。Windows默认GBKLinux默认UTF-8跨平台必乱。第二个原因就是前面反复强调的getLength()。我整理了一个对照表错误写法正确写法后果new String(packet.getData())new String(packet.getData(), 0, packet.getLength(), UTF_8)末尾一堆乱码new String(packet.getData(), UTF_8)同上同上不指定字符集指定UTF_8跨平台乱码第三个原因是缓冲区复用。如果你在循环外建了一个byte[] buffer反复用上一轮的长数据会残留在缓冲区里下一轮短数据覆盖不全就会读到脏数据。解决办法是每次接收前清空缓冲区或者干脆每次新建。我倾向于每次新建代码清晰不容易出错。4.2 服务端收不到包怎么排查服务端收不到包按这个顺序排查基本能定位服务端启动了吗先确认服务端进程在跑端口监听正常。可以用netstat -anp | grep 8888Linux或netstat -ano | findstr 8888Windows看端口有没有被监听。地址对不对客户端连的是127.0.0.1还是局域网IP如果服务端在另一台机器客户端必须填那台机器的真实IP不能填127.0.0.1。防火墙放行了吗这是最常见的坑。云服务器要检查安全组本地要检查系统防火墙。UDP端口要单独放行很多人只放行了TCP忘了UDP。端口被占用了吗如果服务端启动时报BindException说明端口被别的程序占了换个端口。包真的发出去了吗在客户端send之后打印一行日志确认代码执行到了。有时候是客户端逻辑问题根本没发出去。我做过一个速查表贴在下面方便对照现象可能原因排查方法服务端无任何输出包没到达检查IP、端口、防火墙服务端报BindException端口被占用换端口或杀进程客户端receive超时服务端没回或包丢了检查服务端逻辑、网络收到乱码字符集或长度问题统一UTF-8用getLength只能收到第一个包缓冲区或包复用问题每次新建包和缓冲区4.3 UDP丢包了怎么办UDP丢包是常态不是异常。处理方式取决于业务需求。如果业务能容忍丢包比如实时视频、游戏位置同步那就别管它丢就丢了下一帧马上来。硬要重传反而增加延迟得不偿失。如果业务需要可靠有两个选择。一是在应用层自己实现确认重传机制发送方发完等ACK超时没收到就重发收到重复包就丢弃。这个逻辑不难但要处理好超时时间、重传次数、去重。二是在UDP之上用现成的可靠协议比如QUIC不过那又是另一个话题了。我在案例里演示的是最简单的发一条收一条其实已经隐含了一个同步确认客户端发完就等回复收到回复说明这一轮成功了超时说明可能丢了。如果你要连续发多条不等回复那就得自己加序号和ACK了。注意应用层做重传时超时时间别设太短。局域网内50到100毫秒合理公网建议200到500毫秒。设太短会导致大量无谓重传反而加重网络负担。4.4 几个我踩过的坑第一个坑DatagramSocket的receive方法会阻塞如果你在UI线程里调用界面会卡死。正确做法是放到独立线程里或者用setSoTimeout配合循环。这个在写桌面程序时特别容易犯。第二个坑DatagramPacket的getData()返回的数组长度是缓冲区大小不是实际数据长度。我前面强调过但还是要再说一遍因为太容易错了。判断实际长度永远用getLength()。第三个坑服务端回复时如果客户端已经关闭了socket回复的包会发到一个没人监听的端口这个包就丢了服务端不会收到任何错误。UDP就是这样发出去就不管了所以别指望通过send的返回值判断对方收没收到。第四个坑端口号别用字符串拼。有人把端口写成8888然后Integer.parseInt多此一举还容易出错。端口就是int直接用。第五个坑测试时用localhost和127.0.0.1有时候行为不一致某些系统上localhost会解析成IPv6的::1导致绑定IPv4的服务端收不到。统一用127.0.0.1最稳。5. 从案例延伸到实际应用场景5.1 局域网设备发现UDP最经典的应用之一就是局域网设备发现。原理很简单客户端往广播地址255.255.255.255的某个端口发一个探测包局域网内所有监听该端口的设备都会收到然后各自回复自己的信息。这样客户端不用知道设备IP就能发现它们。实现上发送端要开setBroadcast(true)否则广播包发不出去。接收端正常绑定端口接收即可。这个模式在智能家居、打印机发现、局域网游戏联机里用得非常多。相比TCPUDP广播是一对多的天然优势TCP做不到。5.2 实时心跳与状态上报回到开头那个物联网的例子。设备端每隔一秒发一个心跳包包含设备ID和状态服务端收到就更新设备在线状态。丢一两个心跳无所谓下一个马上补上。这种场景用UDP服务端不需要维护成千上万的连接一个socket全搞定资源占用极低。如果要判断设备离线服务端可以记录每个设备最后一次心跳的时间超过比如5秒没收到就标记离线。这个逻辑简单可靠比TCP的断线检测还省事。5.3 什么时候坚决不能用UDP说了这么多UDP的好也得说说什么场景坚决不能用。凡是涉及数据完整性、顺序性、不能丢的一律上TCP。比如文件传输、数据库操作、支付交易、登录认证这些用UDP就是给自己找麻烦。我见过有人为了高性能用UDP传订单数据结果丢了一单赔了不少钱。性能再高数据错了就是零分。判断标准很简单问自己一句这个数据丢一条会怎样。如果答案是无所谓或者下一帧会补上用UDP如果答案是会出大事用TCP。别为了技术而技术合适才是最好的。5.4 后续可以怎么扩展这个案例是个起点你可以基于它做很多扩展。比如加一个简单的应用层协议定义消息格式类型长度内容支持不同类型的消息。比如加一个客户端列表服务端记录所有发过消息的客户端支持群发。比如加一个心跳机制客户端定时发心跳服务端清理超时的客户端。再往深了走可以研究一下Java的NIO用DatagramChannel做非阻塞的UDP通信单线程处理大量并发。不过那是另一个层次的内容了等你把基础的DatagramSocket玩熟了再往上走。我个人在实际操作中的体会是UDP编程的难点不在APIAPI就那么几个方法半天就能学会。真正的难点在于理解它的不可靠本质并且在业务设计上接受它、利用它。很多人写UDP代码时总想着怎么保证不丢结果把代码写得无比复杂反而失去了UDP轻量的优势。正确的思路是先判断业务能不能容忍丢包能容忍就大胆用不能容忍就换TCP别在UDP上硬造可靠性。这个思路转变过来UDP用起来就顺手了。

相关新闻

C# USB摄像头稳定录制方案:AForge+FFmpeg工业级实践

C# USB摄像头稳定录制方案:AForge+FFmpeg工业级实践

简介:本资源是一份面向C#初学者与桌面应用开发者的USB摄像头调用实战项目,聚焦于Windows平台下视频录制与单帧图像保存的核心功能实现。资源提供DirectShow与Media Foundation双框架的代码实践路径,涵盖设备枚举、滤镜图构建、媒体流捕获、文…

2026/10/15 19:05:56 阅读更多 →
【ESP32笔记】ESP中的分区表

【ESP32笔记】ESP中的分区表

本节目标:看懂分区表 CSV 的每一列,会给工程添加自定义分区,并用 esp_partition API 完成擦除、写入、读取一、本节要解决的问题 ESP32 的程序不是"整个 bin 一股脑烧到某个固定地址",而是把整块 flash 划分成多个分区&…

2026/10/15 19:04:55 阅读更多 →
亲和路由(inspect)

亲和路由(inspect)

Inspect 要解决的是“多轮对话在普通选路下被分到不同渠道”导致缓存失效和兼容性出错的问题;它通过回答“值不值得亲和、按什么粒度分组、用哪些稳定字段”三个问题,输出分类、触发原因和内容哈希;它被设计成无外部状态的纯分析器&#xff0…

2026/10/15 19:04:55 阅读更多 →

最新新闻

Claude Code 使用指南:从 Node.js 环境到终端与 IDE 的完整配置

Claude Code 使用指南:从 Node.js 环境到终端与 IDE 的完整配置

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

2026/10/15 19:46:41 阅读更多 →
Redis 技术分享主线:数据结构、缓存三大问题与高可用落地

Redis 技术分享主线:数据结构、缓存三大问题与高可用落地

简介:围绕 Redis 核心技术点的分享课件,适合后端开发、运维人员及对内存数据库感兴趣的学习者快速建立知识框架。PPT 从简介、配置文件、持久化机制到常用命令逐步展开,涵盖每秒 11 万次读、8.1 万次写的高性能表现,string、hash、…

2026/10/15 19:46:41 阅读更多 →
go-gitignore:基于简单树索引的高性能 Go 免提交匹配库

go-gitignore:基于简单树索引的高性能 Go 免提交匹配库

云原生开发工具DevOps容器编排 【免费下载链接】devspace DevSpace - The Fastest Developer Tool for Kubernetes ⚡ Automate your deployment workflow with DevSpace and develop software directly inside Kubernetes. 项目地址: https://gitcode.com/gh_mirro…

2026/10/15 19:46:41 阅读更多 →
常微分方程数值解法详解:从欧拉法到有限差分法的MATLAB实战

常微分方程数值解法详解:从欧拉法到有限差分法的MATLAB实战

常微分方程的数值解法,在工程计算里几乎是绕不开的。不管是电路瞬态分析、化学反应速率模拟,还是机械系统动力学建模,最后都会落到一个“给定导数关系、给初始条件、积分出整条曲线”的问题上。MATLAB里虽然直接有 ode45、ode23 这些现成求解…

2026/10/15 19:46:41 阅读更多 →
基于 Next.js + Notion 搭建个人网站:nextjs-notion-starter-kit 配置、部署与源码原理全解析

基于 Next.js + Notion 搭建个人网站:nextjs-notion-starter-kit 配置、部署与源码原理全解析

前端 【免费下载链接】nextjs-notion-starter-kit Deploy your own Notion-powered website in minutes with Next.js and Vercel. 项目地址: https://gitcode.com/gh_mirrors/ne/nextjs-notion-starter-kit 点击查看 免费下载 本文以 readme.md 为骨架&#xff0c…

2026/10/15 19:46:41 阅读更多 →
多个传感器如何协同作战?World2Agent多传感器组合与fanout传输完整指南

多个传感器如何协同作战?World2Agent多传感器组合与fanout传输完整指南

【免费下载链接】world2agent World2Agent(W2A) is an open protocol that standardizes how Al agents perceive the real world. 项目地址: https://gitcode.com/gh_mirrors/wo/world2agent 点击查看 免费下载 World2Agent(W2A)是一个开放…

2026/10/15 19:45:41 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/15 9:49:14 阅读更多 →