SMS短信的PDU编码解码,附java解码源码

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/xcg8818/article/details/75313431

       发送短消息常用Text和PDU(Protocol Data Unit,协议数据单元)模式。使用Text模式收发短信代码简单,实现起来十分容易,但最大的缺点是不能收发中文短信;而PDU模式不仅支持中文短信,也能发送英文短信。PDU模式收发短信可以使用3种编码:7-bit、8-bit和UCS2编码。7-bit编码用于发送普通的ASCII字符,8-bit编码通常用于发送数据消息,UCS2编码用于发送Unicode字符。一般的PDU编码由A B C D E F G H I J K L M十三项组成。

       举例:08 91 68 31 08 20 05 05 F0 11 00 0D 91 68 31 96 03 29 30 F0 00 00 00 06 C8 32 9B FD 0E 01

A:短信息中心地址长度,2位十六进制数(1字节)。
B:短信息中心号码类型,2位十六进制数。
C:短信息中心号码,B+C的长度将由A中的数据决定。
D:文件头字节,2位十六进制数。
E:信息类型,2位十六进制数。
F:被叫号码长度,2位十六进制数。
G:被叫号码类型,2位十六进制数,取值同B。
H:被叫号码,长度由F中的数据决定。
I:协议标识,2位十六进制数。
J:数据编码方案,2位十六进制数。
K:(1)数据编码方案为8bit时,表示有效期,2位十六进制数。(2)7bit和USC2下,表示时间戳(TP-SCTS)
L:用户数据长度,2位十六进制数。
M:用户数据,其长度由L中的数据决定。J中设定采用UCS2编码,这里是中英文的Unicode字符。

解码代码:

	 //对短信息进行分析
    public synchronized RevSmsVo analyseMessage(String cmtContent) {
		 RevSmsVo revSmsVo=new RevSmsVo();
		 //08 91 68 31 08 20 05 05 F0 11 00 0D 91 68 31 96 03 29 30 F0 00 00 00 06 C8 32 9B FD 0E 01
		 /*
		  	A 08 SMSC地址信息的长度 共8个八位字节(包括91)
			B 91 SMSC地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
			C 68 31 08 20 05 05 F0 SMSC地址 8613800250500,补‘F’凑成偶数个
			D 11 基本参数(TP-MTI/VFP) 发送,TP-VP用相对格式
			E 00 消息基准值(TP-MR) 0
			F 0D 目标地址数字个数 共13个十进制数(不包括91和‘F’)
			G 91 目标地址格式(TON/NPI) 用国际格式号码(在前面加‘+’)
			H 68 31 96 03 29 30 F0 目标地址(TP-DA) 8613693092030,补‘F’凑成偶数个
			I 00 协议标识(TP-PID) 是普通GSM类型,点到点方式
			J 00 用户信息编码方式(TP-DCS) 7-bit编码
			K 00 有效期(TP-VP) 5分钟
			L 06 用户信息长度(TP-UDL) 实际长度6个字节
			M C8 32 9B FD 0E 01 用户信息(TP-UD) “Hello!”
		  */
		 
		 //A:短信息中心地址长度,2位十六进制数(1字节)。
		 StringBuffer sb=new StringBuffer(cmtContent.replace(" ",""));
		 int smsc_len=Integer.parseInt(sb.substring(0,2));
		 sb.delete(0, 2);
		 if(smsc_len>0){
			 //B:短信息中心号码类型,2位十六进制数。
			 String smsc_format=sb.substring(0,2);
			 sb.delete(0, 2);
			 //C:短信息中心号码,B+C的长度将由A中的数据决定。
			 String smsc_code=changeSimCode(sb.substring(0,(smsc_len*2-2))).replaceFirst("F","");
			 if("001".equals(Arith.hexString2binaryString(smsc_format).substring(1, 4)))
				 smsc_code=smsc_code.substring(2);//去国别码,参见TON/NPI标准
			 sb.delete(0, (smsc_len*2-2));
			 MyLog.logger.debug("短信解码调试 > 短信中心号码"+smsc_code);
		 }
		 
		 //D:文件头字节,2位十六进制数。
		 String d=sb.substring(0, 2);
		 sb.delete(0, 2);
		 //E:信息类型,2位十六进制数。
		 if("11".equals(d))
			 sb.delete(0, 2);
		 //F:被叫号码长度,2位十六进制数。0D 目标地址数字个数 共13个十进制数(不包括91和‘F’)
		 int simCodeLength= Integer.parseInt(sb.substring(0,2), 16);
		 if (simCodeLength % 2 != 0)
		   simCodeLength = simCodeLength + 1;
		 MyLog.logger.debug("短信解码调试 > 被叫号码长度:"+simCodeLength);
		 sb.delete(0, 2);
		 
		 //被叫号码格式,2位十六进制数。
		 String smsCode_format=sb.substring(0,2);
		 sb.delete(0, 2);
		 MyLog.logger.debug("短信解码调试 > 被叫号码格式:"+smsCode_format);
		 
		 //G:被叫号码类型,2位十六进制数,取值同B。
		 String simCode=changeSimCode(sb.substring(0,simCodeLength)).replaceFirst("F","");
		 if("001".equals(Arith.hexString2binaryString(smsCode_format).substring(1, 4)))
			 simCode=simCode.substring(2);//去国别码,参见TON/NPI标准
			 
		 revSmsVo.setSimCode(simCode);
		 sb.delete(0, simCodeLength);
		 MyLog.logger.debug("短信解码调试 > 被叫号码"+simCode);
		 
		 //I:协议标识,2位十六进制数。
		 sb.delete(0, 2);
		 //J:数据编码方案,2位十六进制数。
		 int msgFormat= Integer.valueOf(sb.substring(0,2));
		 sb.delete(0, 2);
		 MyLog.logger.debug("短信解码调试 > 数据编码方案"+msgFormat+"(0=7Bit,4=8bit,8=SCS2中文)");
		 //K:7-BIT(有效期,2位十六进制数,FF表示最大),UCS2的时间戳(7对16进制数。即短信中心时间    50208151754500字节反转05/02/18 15:57:45 最后的00代表时区,这里为0)。
		  int msgLength;
		  String msgInfo;
		  switch(msgFormat){
		  case 0://7bit
			  //K:时间戳(7对16进制数。即短信中心时间    50208151754500字节反转05/02/18 15:57:45 最后的00代表时区,这里为0)。
			  sb.delete(0, 14);
			  //L:用户数据长度,2位十六进制数。
			  int len = Integer.parseInt(sb.substring(0,2), 16);
			  //7bit的71个字符,对应字节数71/8+?1,然后成2
			  msgLength=((int) Math.floor(len*7/8)+1)*2;
			  MyLog.logger.debug("短信解码调试 > 用户数据长度(字节):"+len+"("+sb.substring(0,2)+"),16进制字符长度"+msgLength);
			  sb.delete(0, 2);
			  //M:用户数据,其长度由L中的数据决定。
			  msgInfo = sb.substring(0,msgLength);
			  revSmsVo.setSmsContent(decode7bit(msgInfo));
			  break;
		  case 4://8bit
			//K:8-BIT(有效期,2位十六进制数)
			  sb.delete(0, 2);
			  //L:用户数据长度,2位十六进制数。
			  msgLength = Integer.parseInt(sb.substring(0,2), 16);
			  sb.delete(0, 2);
			  //M:用户数据,其长度由L中的数据决定。
			  msgInfo = sb.substring(0,msgLength*2);
			  revSmsVo.setSmsContent(decode8bit(msgInfo));
			  break;
		  case 8://中文
			  //K:时间戳(7对16进制数。即短信中心时间    50208151754500字节反转05/02/18 15:57:45 最后的00代表时区,这里为0)。
			  sb.delete(0, 14);
			  //L:用户数据长度,2位十六进制数。
			  msgLength = Integer.parseInt(sb.substring(0,2), 16);
			  sb.delete(0, 2);
			  //M:用户数据,其长度由L中的数据决定。J中设定采用UCS2编码,这里是中英文的Unicode字符。
			  msgInfo = sb.substring(0,msgLength*2);
			  revSmsVo.setSmsContent(unicode2asc(msgInfo));
			  break;
		  default:
			  break;
		  }
		  MyLog.logger.debug("短信解码调试 > 用户数据"+revSmsVo.getSmsContent());
		  return revSmsVo;
	}

附TON/NPI

例如:0X91

地址类型:10010001       

Bits 7: 始终为1

Bits 6,5,4:Type-of-Number(号码类型):001,代表Internation Number。也即是号码前加“+”。注意:对某些比较特殊的号码,例如手机与小灵通的互通时,这里不能设置为001,而要设置成000,代表号码前没有“+”,否则无法接收。
下面是GSM03.40协议号码类型的解释:
 0 0 0   Unknown
 0 0 1   International number
 0 1 0   National number
 0 1 1   Network specific number
 1 0 0   Subscriber number
 1 0 1   Alphanumeric(coded according to TS03.38 7-bit default alphabet)
 1 1 0   Abbreviated number
 1 1 1   Reserved for extension
 ll not interpret reserved values but will store them as received.

 Bits 3,2,1,0:Numbering-plan-identification(号码鉴别),0000—未知,0001—ISDN/电话号码(E.164/E.163),1111—留作扩展;一般默认为0001,表示电话号码类型的。下面是GSM03.40号码鉴别的解释:
Bits4 3 2 1
0 0 0 0    Unknown
0 0 0 1    ISDN/telephone numbering plan (E.164/E.163)
0 0 1 1    Data numbering plan (X.121)
0 1 0 0    Telex numbering plan
1 0 0 0    National numbering plan
1 0 0 1    Private numbering plan
1 0 1 0    ERMES numbering plan (ETSI DE/PS 3 01-3)
1 1 1 1    Reserved for extension
All other values are reserved.




例如:0X91

地址类型:10010001       

Bits 7: 始终为1

Bits 6,5,4:Type-of-Number(号码类型):001,代表Internation Number。也即是号码前加“+”。注意:对某些比较特殊的号码,例如手机与小灵通的互通时,这里不能设置为001,而要设置成000,代表号码前没有“+”,否则无法接收。
下面是GSM03.40协议号码类型的解释:
 0 0 0   Unknown
 0 0 1   International number
 0 1 0   National number
 0 1 1   Network specific number
 1 0 0   Subscriber number
 1 0 1   Alphanumeric(coded according to TS03.38 7-bit default alphabet)
 1 1 0   Abbreviated number
 1 1 1   Reserved for extension
 ll not interpret reserved values but will store them as received.

 Bits 3,2,1,0:Numbering-plan-identification(号码鉴别),0000—未知,0001—ISDN/电话号码(E.164/E.163),1111—留作扩展;一般默认为0001,表示电话号码类型的。下面是GSM03.40号码鉴别的解释:
Bits4 3 2 1
0 0 0 0    Unknown
0 0 0 1    ISDN/telephone numbering plan (E.164/E.163)
0 0 1 1    Data numbering plan (X.121)
0 1 0 0    Telex numbering plan
1 0 0 0    National numbering plan
1 0 0 1    Private numbering plan
1 0 1 0    ERMES numbering plan (ETSI DE/PS 3 01-3)
1 1 1 1    Reserved for extension
All other values are reserved.

猜你喜欢

转载自blog.csdn.net/xcg8818/article/details/75313431