Java使用DatagramPacket发送UDP数据报已发送但客户端无法接收问题求助
问题根因及修复方案
核心错误(直接导致收不到数据)
客户端receive方法的DatagramSocket未绑定到2029监听端口:
- 你当前写的是
DatagramSocket s = new DatagramSocket();,这会让操作系统随机分配一个空闲本地端口,而服务端是固定往2029端口发送数据报,客户端自然收不到。 - 同时接收用的
DatagramPacket不需要指定目标地址,该参数仅用于发送场景。
其他潜在错误(会导致后续运行异常)
- 服务端receive方法反序列化失败:
DatagramChannel.receive写完ByteBuffer后,position指向写入的最后一位,直接调用bb.array()会把缓冲区中未填充的空字节也带入反序列化流程,触发序列化格式错误。需要先调用bb.flip()切换到读模式,再读取有效长度的字节。 - 资源泄漏:每次调用send/receive方法都新建
DatagramChannel/DatagramSocket实例,且未正常关闭资源,多次调用后会出现端口占满、IO异常问题。 - 多余操作:客户端send方法中已经对
DatagramChannel执行了connect操作,调用send方法时不需要再重复传入目标地址。
修复后的核心代码片段
客户端receive方法修复
public Command receive() throws IOException, ClassNotFoundException { // 绑定到2029端口监听 DatagramSocket s = new DatagramSocket(2029); // 接收用DatagramPacket不需要指定目标地址 DatagramPacket inputPacket = new DatagramPacket(new byte[1024],1024); s.receive(inputPacket); ByteArrayInputStream bais = new ByteArrayInputStream(inputPacket.getData(), 0, inputPacket.getLength()); ObjectInputStream ois = new ObjectInputStream(bais); Command res = (Command) ois.readObject(); // 用完关闭资源 ois.close(); bais.close(); s.close(); return res; }
服务端receive方法修复
public Command receive() throws IOException, ClassNotFoundException { SocketAddress socketAddressChannel = new InetSocketAddress("localhost", 1); DatagramChannel datagramChannel = DatagramChannel.open(); datagramChannel.bind(socketAddressChannel); ByteBuffer bb = ByteBuffer.allocate(1024); datagramChannel.receive(bb); // 切换到读模式,取有效字节 bb.flip(); byte[] validData = new byte[bb.remaining()]; bb.get(validData); ByteArrayInputStream bais = new ByteArrayInputStream(validData); ObjectInputStream ois = new ObjectInputStream(bais); Command command =(Command) ois.readObject(); datagramChannel.close(); ois.close(); bais.close(); return command; }
优化建议
如果是频繁调用收发方法的场景,建议把DatagramChannel、DatagramSocket实例做成类成员变量,初始化一次复用即可,不需要每次调用都新建销毁,性能更高也更稳定。
内容的提问来源于stack exchange,提问作者Alexandr Malkov
相关产品推荐
相关产品推荐

