Java pdu短信解码全面解析
短信协议数据单元(PDU)简介
短信协议数据单元(Protocol Data Unit,PDU)是一种短消息传送协议,它将SMS消息内容进行编码和封装,以方便在移动电话网络上进行传输和接收。在Java中,我们可以使用PDU来解码和编码短信。
短信编码
短信可由两部分组成:短信消息中心号码(SMSC Address)和短信内容(Message)。在将短信进行编码之前,需要将短信消息中心号码和短信文本转换成PDU格式。
短信消息中心号码的PDU编码
短信消息中心号码采用地址格式,它由两个字段组成:地址长度(Address Length)和地址信息(Address Information)。其中,地址长度是一个字节,地址信息则是地址号码。地址信息还包括地址类型,包括国际格式,国内格式和其它格式。
以下示例是以中国移动为例,将+8613800138000转换成PDU格式的过程,需要将+86替换成0x91,然后将每两位数字进行交换,最终得到:0x9183C0013800F0。
public static String encodeSmscAddress(String address) {
int length = (address.length() - (address.startsWith("+") ? 1 : 0)) / 2;
byte[] pdu = new byte[length + 1];
pdu[0] = (byte) length;
for (int i = 0, j = 1; i < length; i++, j += 2) {
pdu[j] = (byte) Integer.parseInt(address.substring(j - 1, j + 1), 16);
}
if (address.startsWith("+")) {
pdu[1] = (byte) 0x91;
}
return HexUtils.bytesToHexString(pdu);
}
短信内容的PDU编码
短信内容的PDU编码需要进行如下处理:
- 对短信文本进行编码,采用7位压缩方式或16位Unicode编码(大多数情况下使用7位压缩方式)。
- 计算消息协议数据单元头部长度并将其转换为16进制字符串。
- 将消息协议数据单元头部和消息文本通过空格分开。
以下示例是将一段文本“I love Java”转换成PDU格式的过程。
public static String encodeMessage(String message) {
int length = message.length();
byte[] data;
int udhLength = 0;
if (length > 160) {
udhLength = 6;
int n = (length + 132 - 1) / 132;
byte[] udhData = new byte[udhLength + 1];
udhData[0] = (byte) udhLength;
udhData[1] = (byte) 0x08;
udhData[2] = (byte) 0x04;
udhData[3] = (byte) ((n >> 8) & 0xff);
udhData[4] = (byte) (n & 0xff);
udhData[5] = (byte) 0x01;
data = new byte[length + udhLength];
System.arraycopy(udhData, 0, data, 0, udhLength);
System.arraycopy(message.getBytes(), 0, data, udhLength, length);
length += 7;
} else {
data = message.getBytes();
}
StringBuilder sb = new StringBuilder();
sb.append(Integer.toHexString(length)).append(":");
sb.append("00").append(":");
sb.append("00").append(":");
sb.append("00").append(":");
sb.append(Integer.toHexString(udhLength)).append(":");
sb.append(HexUtils.bytesToHexString(data));
return sb.toString().toUpperCase();
}
短信解码
短信解码主要是将PDU格式的数据解析成短信消息中心号码和短信内容。
短信消息中心号码的PDU解码
短信消息中心号码的PDU解码需要根据地址类型进行不同的处理,以中国移动为例,地址类型为0x91,其它地址类型根据具体情况而定,采用相应的处理方式解码即可。
public static String decodeSmscAddress(String pdu) {
byte[] bytes = HexUtils.hexStringToBytes(pdu);
int length = bytes[0] & 0xff;
StringBuilder sb = new StringBuilder();
byte digit;
for (int i = 1; i <= length; i++) {
digit = bytes[i];
if ((i == 1) && ((digit & 0xff) == 0x91)) {
sb.append("+");
}
sb.append(String.format("%02X", digit));
if ((i == length) && ((digit & 0x0F) == 0x0F)) {
sb.deleteCharAt(sb.length() - 1);
}
}
return sb.toString();
}
短信内容的PDU解码
短信内容的PDU解码需要从PDU字符串中分离出消息协议数据单元头部和消息文本,然后对消息文本进行反编码。
public static String decodeMessage(String pdu) {
byte[] bytes = HexUtils.hexStringToBytes(pdu);
int udhLength = bytes[4] & 0xff;
byte[] data = new byte[bytes.length - 7 - udhLength];
System.arraycopy(bytes, 7 + udhLength, data, 0, data.length);
int length = Integer.parseInt(pdu.substring(0, 2), 16);
String hexText = HexUtils.bytesToHexString(data);
if ((bytes[6] & 0x03) == 0x03) {
hexText = hexText.substring(0, hexText.length() - 2);
length--;
}
return extractText(hexText, length);
}
该方法中引用的方法extractText() 可以通过以下方式获得:
private static String extractText(String hexText, int length) {
StringBuilder sb = new StringBuilder();
int index = 0;
while (index < hexText.length()) {
int end = Math.min(index + 2, hexText.length());
int i = Integer.parseInt(hexText.substring(index, end), 16);
if ((i & 0x80) == 0x80) {
end = Math.min(index + 4, hexText.length());
int j = Integer.parseInt(hexText.substring(index, end), 16);
sb.append(String.valueOf((char) ((j & 0x7F) << 8 | (i & 0x7F))));
index += 4;
} else {
sb.append(String.valueOf((char) i));
index += 2;
}
}
return sb.toString().substring(0, length);
}
示例
假设我们有这样一条短信,文本为“Hello, world!”,短信消息中心号为+8613800138000。
编码
对短信消息中心号码和短信内容进行编码。
String smscAddress = "+8613800138000";
String message = "Hello, world!";
String pdu1 = encodeSmscAddress(smscAddress);
String pdu2 = encodeMessage(message);
输出结果:
pdu1: 91938310038000F0
pdu2: 0C8BBA9380000AB0040B4AE06B95E06
解码
对PDU字符串进行解码。
String pdu1 = "91938310038000F0";
String pdu2 = "0C8BBA9380000AB0040B4AE06B95E06";
String smscAddress = decodeSmscAddress(pdu1);
String message = decodeMessage(pdu2);
输出结果:
smscAddress: +8613800138000
message: Hello, world!
以上就是Java pdu短信解码的全面攻略,希望能对您有所帮助!
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java pdu短信解码全面解析 - Python技术站