DatagramChannel 实现 UDP 传输的核心是“非阻塞 + Selector 事件驱动 + 直接缓冲区”,需 configureBlocking(false) 后绑定端口并注册 OP_READ;receive() 用 direct buffer 并 clear,返回发送方地址用于回包;send() 前需 flip,目标地址独立指定;Selector 轮询处理就绪事件,attach 可绑定上下文。

Java NIO 中用 DatagramChannel 实现 UDP 传输,核心是围绕“非阻塞 + Selector 事件驱动 + 直接缓冲区”构建高效收发模型。它不依赖连接状态,适合高并发、低延迟的场景,比如实时音视频、游戏心跳、DNS 查询等。
创建并配置通道
必须显式设置为非阻塞,否则无法注册到 Selector:
- 调用
DatagramChannel.open()获取通道实例 - 立即执行
configureBlocking(false) - 用
bind(new InetSocketAddress(port))绑定本地端口(接收用),端口可设为 0 让系统自动分配 - 将通道注册到 Selector,监听
OP_READ—— UDP 不需要OP_WRITE,因为 send() 总是立即返回
高效接收数据
每次 receive() 只读一个完整 UDP 数据报,需注意缓冲区管理与来源识别:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 推荐使用直接缓冲区:
ByteBuffer.allocateDirect(64 * 1024),减少 GC 和内存拷贝 - 每次调用前务必
buffer.clear(),重置 position 和 limit -
receive(buffer)返回SocketAddress,即发送方 IP 和端口,必须保存——这是回包的唯一依据 - 若 buffer 不足,数据被截断,
receive()仍返回实际长度,但内容不完整;应用层应检查是否超出 capacity 并丢弃该包
异步发送数据
UDP 发送无需等待、不保证送达,所以操作极简:
立即学习“Java免费学习笔记(深入)”;
-
send(buffer, remoteAddress)中的 buffer 必须已flip()(limit 设为有效数据长度) - 目标地址在 send 时指定,与 bind 的本地地址无关
- 失败通常抛
IOException或子类如PortUnreachableException,多因路由不可达或 ICMP 目标不可达响应 - 高并发下可将待发数据暂存队列,由独立 I/O 线程批量调用 send,避免主线程陷入系统调用
配合 Selector 进行事件轮询
单个 Selector 可支撑数千个 DatagramChannel,关键在于只处理就绪事件:
- 典型循环:调用
selector.select()→ 遍历selectedKeys()→ 对每个isReadable()的 key 执行 receive → 处理完后调用key.cancel()或保留复用 - 用
select(timeout)控制轮询间隔,平衡响应速度与 CPU 占用;低延迟场景可用selectNow() - 可通过
SelectionKey.attach()关联自定义上下文对象(如会话 ID、解析器),方便在事件回调中传递状态

















