package udptcp;
|
|
import java.util.ArrayList;
|
import java.util.List;
|
|
// ÖØÃüÃûΪPacketParser£¬±íʾÊý¾Ý°ü½âÎöÆ÷
|
public class PacketParser {
|
// Ìí¼ÓÊ®Áù½øÖÆ×Ö·ûÊý×é³£Á¿
|
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
|
// »º³åÇø×Ö½ÚÊý×é
|
private byte[] buffer = new byte[4096];
|
// µ±Ç°»º³åÇøÓÐЧÊý¾Ý³¤¶È
|
private int bufferLength = 0;
|
|
// ×·¼ÓÐÂÊý¾Ýµ½»º³åÇø
|
public void appendData(byte[] newData, int length) {
|
// ¼ì²é»º³åÇøÊÇ·ñ×ã¹»
|
if (bufferLength + length > buffer.length) {
|
// ´´½¨Ðµĸü´ó»º³åÇø
|
byte[] newBuffer = new byte[bufferLength + length];
|
// ¸´ÖÆÔÓÐÊý¾Ý
|
System.arraycopy(buffer, 0, newBuffer, 0, bufferLength);
|
buffer = newBuffer;
|
}
|
// ×·¼ÓÐÂÊý¾Ý
|
System.arraycopy(newData, 0, buffer, bufferLength, length);
|
// ¸üлº³åÇø³¤¶È
|
bufferLength += length;
|
}
|
|
// ÐÂÔö·½·¨£º×Ö½ÚÊý×éתʮÁù½øÖÆ×Ö·û´®
|
public static String bytesToHexString(byte[] bytes) {
|
if (bytes == null) return "";
|
char[] hexChars = new char[bytes.length * 2];
|
for (int j = 0; j < bytes.length; j++) {
|
int v = bytes[j] & 0xFF;
|
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
|
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
|
}
|
return new String(hexChars);
|
}
|
|
// ½âÎö»º³åÇøÖеÄËùÓÐÍêÕûÊý¾Ý°ü
|
public List<DataPacket> parsePackets() {
|
List<DataPacket> packets = new ArrayList<>();
|
int index = 0; // µ±Ç°½âÎöλÖÃË÷Òý
|
|
// ±éÀú»º³åÇø²éÕÒÍêÕûÊý¾Ý°ü
|
while (index <= bufferLength - 4) { // È·±£ÓÐ×ã¹»Êý¾Ý¼ì²é°üÍ·
|
// ¼ì²é°üÍ·±êʶ 0x55 0xAA
|
if (buffer[index] == 0x55 && (buffer[index + 1] & 0xFF) == 0xAA) {
|
// »ñÈ¡°üÀàÐÍ£¨µÚ3×Ö½Ú£©
|
int packetType = buffer[index + 2] & 0xFF;
|
// »ñÈ¡Êý¾Ý³¤¶È£¨µÚ4×Ö½Ú£©
|
int dataLenField = buffer[index + 3] & 0xFF;
|
// ¼ÆËãÍêÕû°ü³¤¶È£¨°üÍ·+Êý¾Ý+УÑ飩
|
int totalPacketLen = 4 + dataLenField + 2; // Ôö¼Ó2×Ö½ÚУÑéλ
|
|
// ¼ì²éÊÇ·ñÓÐ×ã¹»Êý¾Ý¹¹³ÉÍêÕû°ü
|
if (index + totalPacketLen > bufferLength) {
|
break; // Êý¾Ý²»×㣬µÈ´ý¸ü¶àÊý¾Ý
|
}
|
|
// ÌáÈ¡ÍêÕûÊý¾Ý°ü
|
byte[] packetData = new byte[totalPacketLen];
|
System.arraycopy(buffer, index, packetData, 0, totalPacketLen);
|
|
// Ñé֤УÑéºÍ
|
if (verifyChecksum(packetData)) {
|
// ½âÎöµ¥¸öÊý¾Ý°ü
|
DataPacket packet = parseSinglePacket(packetType, packetData);
|
if (packet != null) {
|
packets.add(packet); // Ìí¼Óµ½½á¹ûÁбí
|
}
|
index += totalPacketLen; // ÒÆ¶¯µ½ÏÂÒ»¸ö°ü
|
} else {
|
index++; // УÑéʧ°Ü£¬Ìø¹ýµ±Ç°×Ö½Ú
|
}
|
} else {
|
index++; // ·Ç°üÍ·±êʶ£¬¼ÌÐø²éÕÒ
|
}
|
}
|
|
// ÇåÀíÒÑ´¦ÀíÊý¾Ý
|
if (index > 0) {
|
int remaining = bufferLength - index;
|
if (remaining > 0) {
|
// ÒÆ¶¯Ê£ÓàÊý¾Ýµ½»º³åÇø¿ªÍ·
|
System.arraycopy(buffer, index, buffer, 0, remaining);
|
}
|
bufferLength = remaining; // ¸üлº³åÇø³¤¶È
|
}
|
|
return packets;
|
}
|
|
// УÑéÊý¾Ý°üÍêÕûÐÔ
|
public static boolean verifyChecksum(byte[] data) {
|
// ¼ì²éÊäÈëÊÇ·ñΪnull
|
if (data == null) {
|
throw new IllegalArgumentException("ÊäÈë²»ÄÜΪnull");
|
}
|
|
// ÑéÖ¤³¤¶ÈºÍ°üÍ·
|
if (data.length < 8 || data[0] != 0x55 || data[1] != (byte)0xAA) {
|
throw new IllegalArgumentException("ÊäÈë±ØÐëÒÔ0x55ºÍ0xAA¿ªÍ·ÇÒ³¤¶ÈÖÁÉÙΪ8×Ö½Ú");
|
}
|
|
int sum = 0;
|
// ±éÀúÊý¾Ý²¿·Ö£¨Ìø¹ý°üÍ·ºÍ×îºó2×Ö½ÚУÑéÂ룩
|
for (int i = 2; i < data.length - 2; i++) {
|
// ÎÞ·ûºÅÀÛ¼Ó£¨0x00~0xFF£©
|
sum = (sum + (data[i] & 0xFF)) & 0xFFFF; // ά³Ö16λ·¶Î§
|
}
|
|
// ¼ÆËãУÑéÂ루ȡ·´ºóÈ¡µÍ16룩
|
int checksum = (~sum) & 0xFFFF;
|
|
// °´Ð¡¶ËÐò²ð·ÖУÑéÂ루µÍ×Ö½ÚÔÚǰ£©
|
byte calcLow = (byte)(checksum & 0xFF); // µÍ8λ
|
byte calcHigh = (byte)((checksum >>> 8) & 0xFF); // ¸ß8λ
|
|
// Ö±½Ó±È½Ï×îºóÁ½¸ö×Ö½Ú£¨±ÜÃâ´´½¨Ð¶ÔÏó£©
|
boolean a1=(data[data.length - 2] == calcLow) &&(data[data.length - 1] == calcHigh);
|
return true;
|
}
|
|
// ½âÎöµ¥¸öÊý¾Ý°ü
|
private DataPacket parseSinglePacket(int packetType, byte[] packet) {
|
|
// ´´½¨Êý¾Ý°ü¶ÔÏ󣨰üº¬°üÀàÐÍ£©
|
return new DataPacket(packetType, packet);
|
}
|
|
// Êý¾Ý°üÄÚ²¿Àà
|
public static class DataPacket {
|
private final int packetType; // °üÀàÐÍ
|
private final byte[] packet;//°üÊý¾Ý
|
|
|
public DataPacket(int packetType, byte[] packet) {
|
this.packetType = packetType;
|
this.packet = packet;
|
}
|
|
// »ñÈ¡°üÀàÐÍ
|
public int getPacketType() {
|
return packetType;
|
}
|
|
// °üÊý¾Ý
|
public byte[] getPacket() {
|
return packet;
|
}
|
|
}
|
|
// HEX×Ö·û´®×ª×Ö½ÚÊý×é
|
public static byte[] hexStringToBytes(String hex) {
|
// ÒÆ³ý¿Õ¸ñ
|
hex = hex.replaceAll("\\s", "");
|
int len = hex.length();
|
// ´´½¨½á¹ûÊý×é
|
byte[] data = new byte[len / 2];
|
// ÿÁ½¸ö×Ö·ûת»»Ò»¸ö×Ö½Ú
|
for (int i = 0; i < len; i += 2) {
|
// ¸ßλת»»
|
int high = Character.digit(hex.charAt(i), 16) << 4;
|
// µÍλת»»
|
int low = Character.digit(hex.charAt(i + 1), 16);
|
data[i / 2] = (byte) (high | low);
|
}
|
return data;
|
}
|
|
|
/**Êä³öУÑéÂë*/
|
public static String calculateChecksum(String input) {
|
// ¼ì²éÊäÈëÊÇ·ñΪ¿Õ
|
if (input == null) {
|
throw new IllegalArgumentException("ÊäÈë²»ÄÜΪnull");
|
}
|
|
// ÒÆ³ýËùÓпոñ
|
String cleanInput = input.replaceAll("\\s", "");
|
|
// ÑéÖ¤´¦ÀíºóµÄ×Ö·û´®
|
if (cleanInput.length() < 8 || !cleanInput.startsWith("55AA")) {
|
throw new IllegalArgumentException("ÊäÈë×Ö·û´®±ØÐëÒÔ55AA¿ªÍ·ÇÒ³¤¶ÈÖÁÉÙΪ8£¨È¥³ý¿Õ¸ñºó£©");
|
}
|
|
// È¥µô°üÍ·(55AA)ºÍ×îºó4¸ö×Ö·û
|
String dataPart = cleanInput.substring(4, cleanInput.length() - 4);
|
|
// ¼ì²éÖм䲿·Ö³¤¶ÈÊÇ·ñΪżÊý
|
if (dataPart.length() % 2 != 0) {
|
throw new IllegalArgumentException("Öм䲿·Ö³¤¶È±ØÐëÊÇżÊý£¨È¥³ý¿Õ¸ñºó£©");
|
}
|
|
int sum = 0;
|
// ÿÁ½¸ö×Ö·û½âÎöΪһ¸ö×Ö½Ú
|
for (int i = 0; i < dataPart.length(); i += 2) {
|
String byteStr = dataPart.substring(i, i + 2);
|
int byteValue = Integer.parseInt(byteStr, 16);
|
sum = (sum + byteValue) & 0xFFFF; // ±£³Ö16λ·¶Î§
|
}
|
|
// È¡·´²¢±£³Ö16λ
|
int checksum = (~sum) & 0xFFFF;
|
|
// ÏÔʽ´¦Àí¸ßλÔÚǰ¸ñʽ
|
int lowByte= (checksum >>> 8) & 0xFF; // ¸ß8λ
|
int highByte= checksum & 0xFF; // µÍ8λ
|
|
// ¸ñʽ»¯Îª4λʮÁù½øÖÆ×Ö·û´®£¨´óд£©£¬¸ßλÔÚǰ
|
return String.format("%02X%02X", highByte, lowByte);
|
}
|
}
|