跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
代码酷
搜索
搜索
中文(中国大陆)
外观
创建账号
登录
个人工具
创建账号
登录
未登录编辑者的页面
了解详情
贡献
讨论
编辑“︁
Java DatagramPacket
”︁
页面
讨论
大陆简体
阅读
编辑
编辑源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
编辑
编辑源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
外观
移至侧栏
隐藏
您的更改会在有权核准的用户核准后向读者展示。
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
{{DISPLAYTITLE:Java DatagramPacket}} '''Java DatagramPacket''' 是 Java 网络编程中用于实现无连接数据包传输的核心类,属于 <code>java.net</code> 包。它通常与 [[Java DatagramSocket|DatagramSocket]] 配合使用,支持 [[UDP]](用户数据报协议)通信。与面向连接的 [[TCP]] 不同,UDP 不保证数据包的顺序或可靠性,但具有低延迟和高吞吐量的特点,适用于实时应用(如视频流、在线游戏等)。 == 概述 == DatagramPacket 表示一个数据包,包含以下核心信息: * '''数据缓冲区'''(byte[]):存储实际传输的数据 * '''长度''':数据包的有效数据长度 * '''目标地址'''(IP + 端口):用于发送数据包 * '''源地址'''(IP + 端口):接收数据包时自动填充 === 类签名 === <syntaxhighlight lang="java"> public final class DatagramPacket extends Object </syntaxhighlight> == 构造函数 == DatagramPacket 提供两种主要构造函数: === 接收数据包 === <syntaxhighlight lang="java"> // 创建用于接收的包(不指定目标地址) DatagramPacket(byte[] buf, int length) </syntaxhighlight> === 发送数据包 === <syntaxhighlight lang="java"> // 创建用于发送的包(指定目标地址) DatagramPacket(byte[] buf, int length, InetAddress address, int port) </syntaxhighlight> == 核心方法 == {| class="wikitable" |- ! 方法 !! 描述 |- | <code>byte[] getData()</code> || 返回数据缓冲区 |- | <code>int getLength()</code> || 返回有效数据长度 |- | <code>InetAddress getAddress()</code> || 返回目标/源地址 |- | <code>int getPort()</code> || 返回目标/源端口 |- | <code>void setData(byte[] buf)</code> || 设置数据缓冲区 |- | <code>void setLength(int length)</code> || 设置有效数据长度 |} == 基础示例 == === 发送端代码 === <syntaxhighlight lang="java"> import java.net.*; public class UDPSender { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(); String message = "Hello UDP!"; byte[] data = message.getBytes(); InetAddress address = InetAddress.getByName("localhost"); DatagramPacket packet = new DatagramPacket( data, data.length, address, 9876); socket.send(packet); System.out.println("Sent: " + message); socket.close(); } } </syntaxhighlight> === 接收端代码 === <syntaxhighlight lang="java"> import java.net.*; public class UDPReceiver { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(9876); byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer, buffer.length); socket.receive(packet); String received = new String( packet.getData(), 0, packet.getLength()); System.out.println("Received: " + received); socket.close(); } } </syntaxhighlight> === 执行结果 === 先运行接收端,再运行发送端: <pre> 接收端输出: Received: Hello UDP! 发送端输出: Sent: Hello UDP! </pre> == 高级应用 == === 数据包分片 === UDP 最大包长受 [[MTU]] 限制(通常 1500 字节)。大文件需要分片传输: <syntaxhighlight lang="java"> // 发送分片示例 byte[] largeData = /* 大文件数据 */; int chunkSize = 1400; // 小于MTU for (int i = 0; i < largeData.length; i += chunkSize) { int length = Math.min(chunkSize, largeData.length - i); DatagramPacket chunk = new DatagramPacket( largeData, i, length, address, port); socket.send(chunk); } </syntaxhighlight> === 校验和验证 === UDP 不保证可靠性,可手动添加校验: <syntaxhighlight lang="java"> // 添加简单校验和 byte[] originalData = /* 原始数据 */; byte checksum = calculateChecksum(originalData); byte[] packetData = new byte[originalData.length + 1]; System.arraycopy(originalData, 0, packetData, 0, originalData.length); packetData[packetData.length - 1] = checksum; // 接收端验证 byte receivedChecksum = packetData[packetData.length - 1]; if (receivedChecksum != calculateChecksum( Arrays.copyOf(packetData, packetData.length - 1))) { throw new IOException("Checksum mismatch"); } </syntaxhighlight> == 协议分析 == DatagramPacket 在 UDP 协议栈中的位置: <mermaid> sequenceDiagram participant App as 应用程序 participant Java as Java API participant OS as 操作系统 participant Net as 网络 App->>Java: 创建DatagramPacket Java->>OS: 调用系统socket API OS->>Net: 发送UDP数据报 Net-->>OS: 接收UDP数据报 OS-->>Java: 填充DatagramPacket Java-->>App: 返回数据 </mermaid> == 性能考量 == * '''缓冲区复用''':避免频繁创建新缓冲区 * '''线程模型''':考虑使用 [[NIO]] 的非阻塞模式处理高并发 * '''超时设置''':通过 <code>setSoTimeout()</code> 避免无限等待 == 安全实践 == * 验证数据包来源(防止IP欺骗): <syntaxhighlight lang="java"> if (!packet.getAddress().equals(trustedAddress)) { throw new SecurityException("Untrusted source"); } </syntaxhighlight> * 限制数据包大小: <syntaxhighlight lang="java"> if (packet.getLength() > MAX_ALLOWED_SIZE) { throw new IOException("Packet too large"); } </syntaxhighlight> == 实际应用场景 == === 网络游戏位置同步 === 客户端每秒发送多次玩家位置数据包: <syntaxhighlight lang="java"> // 游戏客户端发送位置数据 class PlayerPosition { float x, y, z; long timestamp; } ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); dos.writeFloat(x); dos.writeFloat(y); dos.writeFloat(z); dos.writeLong(System.currentTimeMillis()); DatagramPacket packet = new DatagramPacket( baos.toByteArray(), baos.size(), serverAddress, port); socket.send(packet); </syntaxhighlight> === IoT 设备状态上报 === 传感器设备定期发送状态数据: <syntaxhighlight lang="java"> // 温度传感器数据包结构 byte[] createSensorPacket(float temp, int battery) { byte[] data = new byte[5]; data[0] = (byte)(temp * 10); // 0.1度精度 data[1] = (byte)((int)(temp * 100) % 10); System.arraycopy( ByteBuffer.allocate(4).putInt(battery).array(), 0, data, 2, 3); // 3字节存储电量 return data; } </syntaxhighlight> == 常见问题 == {{Q&A |question = 为什么我的 DatagramPacket 接收不到数据? |answer = 可能原因: * 防火墙/安全组阻止了UDP端口 * 发送方未正确指定目标端口 * 接收缓冲区小于发送的数据包 * 网络路由问题(UDP无重传机制) }} {{Q&A |question = 如何获取发送方的地址? |answer = 接收数据包后调用: <syntaxhighlight lang="java"> InetAddress senderAddress = packet.getAddress(); int senderPort = packet.getPort(); </syntaxhighlight> }} == 数学原理 == UDP 校验和计算(RFC 1071): <math> \text{checksum} = \overline{\sum_{i=1}^n (data_i \ll 8) + data_{i+1}} </math> 其中: * <math>\overline{x}</math> 表示按位取反 * <math>\ll</math> 表示左移运算 * 求和使用16位补码运算 == 参见 == * [[Java DatagramSocket]] * [[Java NIO DatagramChannel]] * [[UDP协议]] * [[网络编程基础]] [[Category:Java网络编程]] [[Category:Java类库]] [[Category:编程语言]] [[Category:Java]]
摘要:
请注意,所有对代码酷的贡献均被视为依照知识共享署名-非商业性使用-相同方式共享发表(详情请见
代码酷:著作权
)。如果您不希望您的文字作品被随意编辑和分发传播,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)
该页面使用的模板:
模板:Q&A
(
编辑
)