Java NIO中DatagramChannel实现UDP通信需配置非阻塞并绑定本地端口,支持connected与非connected两种发送模式,接收依赖receive()或Selector,须妥善处理异常及资源释放。

Java NIO 中使用 DatagramChannel 实现 UDP 通信,核心在于非阻塞模式下的事件驱动处理,配合 Selector 可高效管理多个 UDP 端口;但要注意 UDP 本身无连接、不可靠,应用层需自行处理丢包、乱序、重复等问题。
创建并绑定 DatagramChannel
UDP 通信前必须显式绑定本地地址和端口(即使只发不收),否则发送可能失败(尤其在 Windows 上);DatagramChannel 默认阻塞,如需配合 Selector 必须调用 configureBlocking(false)。
- 创建通道:
DatagramChannel.open() - 设置非阻塞:
channel.configureBlocking(false) - 绑定本地地址:
channel.bind(new InetSocketAddress("localhost", 8080))(端口为 0 表示系统自动分配) - 若仅用于发送且不接收响应,仍建议绑定一个临时端口(如
bind(new InetSocketAddress(0))),避免某些防火墙或安全策略拦截未绑定的 UDP 包
发送数据:直接 write 或通过 connected 模式
UDP 是无连接协议,每次发送都需指定目标地址。有两种常用方式:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
-
非 connected 模式:调用
channel.send(ByteBuffer, SocketAddress),每次传入目标地址,适合向多个不同地址发包 -
connected 模式:先调用
channel.connect(remoteAddr),之后可用channel.write(ByteBuffer)直接发送,系统自动发往已连接地址;该模式还能过滤非目标地址的入站包(内核层面丢弃),提升安全性与效率 - 注意:
write()在非阻塞模式下可能返回 0(缓冲区满或系统限制),需检查返回值并重试;send()则总是尝试发送,返回实际写入字节数
接收数据:使用 receive() 或注册到 Selector
接收端需主动调用 receive(ByteBuffer) 获取数据,并解析源地址;若用 Selector,需注册 OP_READ 事件。
立即学习“Java免费学习笔记(深入)”;
-
receive()返回SocketAddress,即发送方地址,可用于构建响应(如实现简单请求-应答模型) - ByteBuffer 需提前
clear()或flip()(接收前clear(),收到后flip()读取) - 注册到 Selector 时,
receive()不会阻塞,但需确保 ByteBuffer 有足够空间(UDP 包最大约 64KB,建议预分配 ≥65536 字节) - 若通道处于 connected 模式,
receive()仍可工作,但只会收到目标地址的数据;未 connect 时则接收所有发到本端口的 UDP 包
异常处理与资源释放
UDP 通信中常见异常包括 IOException(网络中断、权限不足)、SecurityException(无权绑定特权端口)、PortUnreachableException(ICMP “端口不可达” 报文,表示对方主机无服务监听)。
- 捕获
PortUnreachableException可判断远端服务是否存活(但并非所有系统/防火墙都返回该 ICMP) - 关闭通道前应调用
channel.close();若使用了Selector,记得取消对应SelectionKey - 推荐使用 try-with-resources(
DatagramChannel实现AutoCloseable)保证资源释放 - 生产环境建议加日志记录异常及丢包情况(如
receive()返回 null 表示无数据可读,非错误)

















