Java UDP连接下如何为DatagramPacket添加序列号并在服务端读取
问题根因
- 你当前的序列化顺序是文件内容在前,序列号在后,int类型序列号固定占4个字节,但服务端无法提前知道文件内容的实际长度,无法定位序列号的起始位置
- 服务端大概率是直接将整包数据直接转成字符串输出,末尾4字节的序列号被当成不可见字符直接忽略,因此无法读取
修复方案
客户端改造
将序列号放到数据包的最前面,固定前4字节为序列号,剩余部分为业务数据,修改拼接逻辑如下:
//concatenate sequence number with file: ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(outputStream); // 先写序列号(固定占4字节,放在最开头方便解析) dos.writeInt(SN); // 再写文件内容,指定字符集避免不同环境乱码 dos.write(fileText.getBytes(StandardCharsets.UTF_8)); dos.flush(); byte[] concatData = outputStream.toByteArray(); sendData = concatData; // 后续发送逻辑不变 DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 102); clientSocket.send(sendPacket); // 用完记得关闭流 dos.close(); outputStream.close(); clientSocket.close();
服务端解析逻辑
接收数据包后,先读取前4字节拿到序列号,再解析剩余内容:
DatagramSocket serverSocket = new DatagramSocket(102); byte[] receiveBuffer = new byte[1024]; DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length); // 接收数据包 serverSocket.receive(receivePacket); byte[] packetData = receivePacket.getData(); int packetLen = receivePacket.getLength(); // 解析数据 ByteArrayInputStream bais = new ByteArrayInputStream(packetData, 0, packetLen); DataInputStream dis = new DataInputStream(bais); // 先读前4字节获取序列号 int sn = dis.readInt(); // 读取剩余所有字节为文件内容 byte[] contentBytes = dis.readAllBytes(); String fileContent = new String(contentBytes, StandardCharsets.UTF_8); // 打印验证 System.out.println("序列号:" + sn); System.out.println("文件内容:" + fileContent); // 关闭流 dis.close(); bais.close(); serverSocket.close();
注意事项
- 单次发送的数据包总大小不要超过UDP最大报文限制(通常建议不超过1472字节,避免IP层分片丢包)
- 序列号自增逻辑可以在每次发送完一个包后执行
SN++即可实现每个包携带唯一序列号
内容的提问来源于stack exchange,提问作者Luke Delves
相关产品推荐
相关产品推荐

