DatagramChannel 需配置为非阻塞、绑定端口并注册到 Selector 实现高效 UDP I/O 复用;接收用 receive() 获取带源地址的报文,发送需指定目标地址(或先 connect);注意 buffer 管理与 key 清理。

用 DatagramChannel 收发 UDP 数据包,核心是把它配置为非阻塞模式、绑定本地端口、配合 Selector 实现高效 I/O 复用。它比传统 DatagramSocket 更适合高并发场景,但使用门槛略高。
创建并配置 DatagramChannel
必须显式调用 configureBlocking(false),否则无法注册到 Selector;同时需绑定本地地址(否则发送可能成功,但接收会失败):
- 调用
DatagramChannel.open()获取通道 - 立即执行
configureBlocking(false) - 用
bind(new InetSocketAddress(port))绑定端口(port = 0表示系统自动分配) - 若要发送给特定目标,无需提前 connect;但调用
connect()后,只能收发该地址的数据,且write()可直接传ByteBuffer,不用再指定InetSocketAddress
注册到 Selector 并监听读写事件
DatagramChannel 只支持 OP_READ 和 OP_WRITE,但实际中极少注册 OP_WRITE —— 因为 UDP 发送通常不阻塞,写操作几乎总能立即完成:
- 创建
Selector:Selector.open() - 调用
channel.register(selector, SelectionKey.OP_READ) - 在事件循环中调用
selector.select()等待就绪,再遍历selectedKeys() - 对每个就绪的 key,检查是否为
OP_READ,然后调用channel.receive(buffer)
接收数据:用 receive() 读取带源地址的报文
receive(ByteBuffer) 是关键方法,它会把数据填入 buffer,并返回发送方的 InetSocketAddress —— 这是实现“响应式通信”的基础:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
立即学习“Java免费学习笔记(深入)”;
- buffer 需提前
clear(),接收后调用flip()提取有效字节 - 返回值为
null表示无数据可读(非阻塞模式下正常现象) - 返回的 address 可用于后续
send()响应,例如:channel.send(buffer, senderAddress) - 注意 buffer 容量要足够大,否则数据被截断且无提示
发送数据:send() 需明确指定目标地址
除非已调用 connect(),否则每次 send() 都必须传入目标 InetSocketAddress:
- 发送前确保 buffer 处于
position=0、limit=有效长度状态(可用flip()或rewind()+limit(len)) - 调用
channel.send(buffer, targetAddress),返回实际发送字节数(通常等于 buffer 中剩余字节数) - 若 channel 已 connect,可直接
send(buffer),目标地址固定为 connect 时指定的那个 - UDP 不保证送达,也不通知发送失败(如目标不可达),应用层需自行处理超时或重传逻辑
不复杂但容易忽略:记得在 receive() 后及时 compact() 或 clear() buffer,避免下次读取时 position/limit 错乱;selector 循环中处理完每个 key 后,务必调用 key.remove() 或确认其不再有效,防止重复处理。

















