`
jxxms
  • 浏览: 104485 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论
阅读更多

Wap push的发送应该有两种途径,一个是通过PAP协议,另外一个是通过SMPP协议。其中SMPP是一个基本协议,在中国主要有三个派生的协议:中国移动的CMPP协议,中国联通的SGIP(在CDMA上面好像是ETIP),以及小灵通的SMGP。据说中国移动没有在公网开放PAP协议,于是只好使用CMPP协议来进行wap push发送了,不知道其他的运营商是否也是如此。上面提到的各种协议都是公开的,通过Google搜索就可以得到。光得到协议没有什么意义,因为你还需要知道wap push网关的IP和Port,以及运营商给你发放的帐号和密码。而最为头痛的是,你研究下载下来的协议的时候,至少会遇到下列几个大问题:
1、协议可能不正确
2、协议内容语焉不详,或者具有二义性
3、没有任何实际例子

如果你能够进入运营商的实验室会更好,因为可以得到一些技术支持。不过也不要开心的太早,你还会遇到下列问题:
1、运营商并不清楚协议的技术细节,因为实际上是由运营商的硬件提供商所代为开发的(至少我看起来的是这样的)
2、硬件提供商的技术人员也不一定清楚非常深入的技术细节,天晓得到底谁才知道这些该死的协议的技术细节。
3、在实验室里面的技术人员至少可以帮你抓一个包,指出你的包跟标准的包有什么区别。如果没有大的区别的时候仍然出错,那技术人员也无能为力了。

在开发Wap push的时候跟实验室的技术人员聊天,据说以前其他的人员连接上去的时候,还曾经遇到过MD5算法不标准导致验证不通过的问题。幸亏我用的.NET,不会出现这种问题,不然验证不通过你还不知道是验证的明文格式不对,还是其他的什么问题,总之是不可能进行调试的。而我遇到的问题则主要是文档迷惑人造成的,比如说协议里面有一个字段叫做SourceAddress,实际上要求你填入的是SpID,而SourceID的字段却要求你填入SourceAddress。看完那堆文档我的大脑几乎要被搅成浆糊了,希望你会好一点。

实际上这个CMPP的协议是用来发送短消息的,包括普通的短消息、彩信以及WapPush等。具体你要发送什么类型的消息,需要设置MessageType字段和MessageContent字段。因此如果你要发送的事彩信,那么还得找跟彩信相关的资料,尤其是数据包结构。而我则非常郁闷的发现,关于WapPush数据包的资料非常的少,少的不可置信。前面那个中文资料算是帮了我一把,对比了实验室抓取的另外一个数据包之后,至少看懂了部分的内容,并且某个品牌的手机能够收到。可是里面提到的WapPush Header1之类的内容到底是什么意思,以及如何编写其他标记等,统统不知道。

Goo了半天才搞懂,原来WapPush包发送的内容实际上跟PAP发送的XML是一回事,但是经过了压缩。压缩之后的格式叫做WBXML,这种格式将一些标记用代码来表示,例如数值0x01表示上一个标记结束(</xxx>之类的)。然而WBXML的缩略标记分为两部分,一部分是所有类型的XML都通用的,另一部分是不同类型的XML有着不同的解释。而WBXML的Spec只提到了:
2  "-//WAPFORUM//DTD WML 1.0//EN" (WML 1.0)
3  "-//WAPFORUM//DTD WTA 1.0//EN" (WTA Event 1.0)
4  "-//WAPFORUM//DTD WML 1.1//EN" (WML 1.1)

这三种类型,而我们所做的WapPush使用的是
5  "-//WAPFORUM//DTD SI 1.0//EN

关于这里面的内容我没有能够找到任何资料。即使到了这里,我们也只是了解了Header后面的内容,而MessageContent里面的内容则需要从

0B05040B8423F00003030101         ’Wap Push Header 1

29060603AE81EA8DCA   'Wap Push header 2


这里开始发送,但是这些是什么东东呢?我不知道,等高手来解答了。不过在这里我可以提供另外一组有效的Wap Push Header:

//    0x06, 0x05, 0x04, 0x0B, 0x84, 0x23, 0xF0,     ' Wap Push Header 1
//    0x25, 0x06, 0x01, 0xAE,                                     ' Wap Push header 2

另外再奉送一下我实验成功的(至少在索爱T618上面必然成功的)一个MessageContent结构:
// 第一部分 WapPushHeader1:
  static private readonly byte[] WapPushHeader1 = new byte[]
   {
//    0x06, 0x05, 0x04, 0x0B, 0x84, 0x23, 0xF0,
    0x0B, 0x05, 0x04, 0x0B, 0x84, 0x23, 0xF0, 0x00, 0x03, 0x03, 0x01, 0x01,
   };
// 第二部分 WapPushHeader2:
  static private readonly byte[] WapPushHeader2 = new byte[]
   {
//    0x25, 0x06, 0x01, 0xAE,
    0x29, 0x06, 0x06, 0x03, 0xAE, 0x81, 0xEA, 0x8D, 0xCA,
   };
// 第三部分 WapPushIndicator (and some other things):
  static private readonly byte[] WapPushIndicator = new byte[]
   {
    0x02, 0x05, 0x6A, 0x00, 0x45, 0xC6, 0x0C, 0x03,
   };
// 第四部分是一个UTF8编码的WapPush连接的Url地址,
// 用户在手机上收到该短信之后点击“下载”或者“连接”之类的按钮之后,
// 就会转到这一个地址。
// 注意,Url地址需要把"http://"去掉,
// 因为上面的WapPushIndicator倒数第二个0x0C就是href = "http://"

// 第五部分Wap Push Display Text Header:
// 其中的0x00是上面的WapPushUrl文字结束标志
// 0x01是上面的<indication>标志(Indicator倒数第三个的0xC6)的结束符
// </indication>
  static private readonly byte[] WapPushDisplayTextHeader = new byte[]
   {
    0x00, 0x01, 0x03,
   };

// 第六部分是一个UTF-8编码的消息文字,用户收到该消息之后就会显示这里面的内容。

// 第七部分是消息结束部分,0x00是消息文字的结束部分,后面两个是上面一些标志的结束符。
  static private readonly byte[] EndOfWapPush = new byte[]
   {
    0x00, 0x01, 0x01,
   };

将这几个部分顺序组合起来,就是MessageContent的内容了。

<script type="text/javascript"></script>

 

 

 

 

 

wap push格式

00     ’SMSC Len。用手机上设置短信中心号码
51     ’submit type
00     ’SMS_TP_Message_Reference type
0B    ’对方电话的长度
A1     ’Number type
13175639296F6       ’电话号码:13573629696
00     ’SMS_TP_PID
F5     ’SMS DCS
A744         ’SMS available date
0B05040B8423F00003030101         ’Wap Push Header 1
29060603AE81EA8DCA   'Wap Push header 2
02
05  '-//WAPFORUM//DTD SI 1.0//EN
6A  'UTF-8
00
45  '<si>
C6  '<indication
08  '<action=signal-high>
0C  'href="http://
03  '字符串开始
687474703A2F2F3231382E35392E3133382E35343A32303030  'URL:   http://218.59.138.54:2000
00  'URL 字符串结束
01  '>
03  '内容描述字符串开始
'这里就是显示给用户的内容,用utf-8编码。
9A6C5EF6671D       '内容描述:马延朝
00  '内容描述字符串结束
01  '</indication>"
01  '</si>
可以只能显示很少的汉字,请高手指点怎么分包发送更多的汉字?

 

一下方法是经过验证的。

TrxID  =一个随机数
    fullStr = "0605040B8423F0" & TrxID & "0601AE"
    fullStr = fullStr & "02056A0045C6080C03"
    fullStr = fullStr & StrToHex(TheURL, 2)
    fullStr = fullStr & "001103" & "0102"
    fullStr = fullStr & "40494400080AC307" & Format(Now, "yyyymmddhhmmss")
    fullStr = fullStr & "10C304" & "20990101" & "0103"
    fullStr = fullStr & StrToHex(MServiceName, 2) & "000101"


分段发送的

例如  URL:wap.gd.monternet.com/?userType=B&serviceID=04020028 提示信息:神秘激情地带,江湖儿女情长神秘激情地带,江湖儿女情长神秘激情地带,江湖儿女情长
第一包:
0B05040B8423F0000355020155060403AE81EA02056A0045C60C037761702E67642E6D6F6E74657
26E65742E636F6D2F3F75736572547970653D42267365727669636549443D303430323030323800
070103E7A59EE7A798E6BF80E68385E59CB0E5B8A62CE6B19FE6B996E584BFE5A5B3E68385E995BF
E7A59EE7A798E6BF80E68385E59CB0E5B8A62C 
第二包:
0B05040B8423F00003550202E6B19FE6B996E584BFE5A5B3E68385E995BFE7A59EE7A798E6BF80E6
8385E59CB0E5B8A62CE6B19FE6B996E584BFE5A5B3E68385E995BF000101 ,解释可参考WDP WSP,我就不具体说了


0B是头的总长度
05040B8423F0是固定的,表示接下来是一个WAP PUSH
分包的关键是0003550201,对应GSM 03.40里9.2.3.24.1,00表示是Concatenated Short Messages,03是长度,55是reference number,楼主在这儿固定编码会有问题的,如果同时下发两条这样的多包短信给同一个手机,手机就区分不开了,02表示分成2个短信发送,01是当前包的序号。


一个扩展包wappush包是这么构成的
WDP + WSP + SI/SL

如果长度超常(短信一个包的Content不要超过140)

就要分解成

WDP1 + (WSP+SI/SL)的part 1
WDP2 + (WSP+SI/SL)的part 2
...
WDPN + (WSP+SI/SL)的part N

 

如单包
WDP: 06 05 04 0B 84 23 F0
WSP: ...
SI/SL:...

双包是
第1包
WDP: 0B 05 04 0B 84 23 F0 00 03 01 02 01
Part1: ...

// 00 - UDH IE Tag
// 03 - UDH SAR IE Length
// 01 - Refrence
// 02 - Total Packet
// 01 - Current Packet

第2包
WDP: 0B 05 04 0B 84 23 F0 00 03 01 02 02
Part2:...


WDP参考相关文档。

 

=====================================================
首先,构造一个Push消息体:

02
05  '-//WAPFORUM//DTD SI 1.0//EN
6A  'UTF-8
00
45  '<si>
C6  '<indication
08  '<action=signal-high>
0C  'href="http://
03  '字符串开始
这里就是url从"http://"以后的那部分的每个字符的ASCII码
00  '字符串结束
0A  'created=
C3  '时间
07  '7个字节,也可以是04,下面就只需要年月日就可以了
20 03 01 01 00 00 00 '年,月,日,时,分,秒,格式如何一看就明白吧。
10  'si_expires=
C3  '时间
07  '跟上面一样
20 04 01 01 00 00 00
01  '>
03  '字符串开始
这里就是显示给用户的内容,用utf-8编码。
utf-8编码,英文字符直接用ascii码;中文如果unicode是(二进制)abcdefgh ijklmnop,
那么utf-8就会变成1110abcd 10efghij 10klmnop
00  '字符串结束
01  '</indication>"
01  '</si>

有了Push消息体之后,需要在前面增加一个Push PDU
81  'transaction id (connectionless WSP)
06  'pdu type (06=push)
06  'Headers len
03 AE 81 EA    'content type: application/vnd.wap.sic; charset=utf-8
8D    'content-length
XX  '这里就是Push消息体的长度。如果消息体长度小于128,那么就要加上128。例如是93个字节,那么需要填入DD
'至于大于127怎么处理,按照协议好像应该是这样,例如原来的二进制abcdefgh,那么就要弄成两个字节:
'1000000a 1bcdefgh,但是尝试还没成功

在然后,还要在前面增加一个UDH
06 'User Data Header Length (6 bytes)
05 'UDH Item Element id (Port Numbers)
04 'UDH IE length (4 bytes)
0B 84   'destination port number
23 F0   'origin port number

如果所有这些加起来大于140个字节,那么就需要修改UDH头,分成两条短消息串联。但是没有尝试成功。

发送的时候,udhi=1,pid=0,dcs=4
Nokia 3650/7650肯定OK,motorola t720肯定ok,siemens 3118,3618肯定不行,其他的还没尝试。

同样的技术可以用来发送mms通知、fundown的铃声图片。

需要解决的问题:长于127字节/两条短信的时候该怎么办。

 

 

 

 

 

1.1. 基本知识

短信开发指通过串口 at 命令驱动短信进行短信发送和接收操作。

java 主要使用 javax.comm 包进行开发,

sun 公司网上地址 http://java.sun.com/products/javacomm/

使用工具 windows 自带超级终端

 

短信操作分为三种模式 block,pdu Text

短信传送有三种编码 7 位, 8 位, UniCode

at 命令 ,at 命令是驱动短信设备的标准工业命令,除了业界的标准之外,每个厂商可能会对其进行扩展,不过一般来说,标准命令应该够用,这次用的是西门子 tc35i ,有专门的 at 命令文档。

 

 

1.1.1.     相关文档

Gsm03.38 规范: Alphabets and language-specific information 着重介绍短信发送中对字符集的控制部分

Gsm03.40 规范: Technical realization of the Short Message Service (SMS) Point-to-Point (PP) 详细介绍各种不同短信的不同实现

Gsm07.05 规范: Use of Data Terminal Equipment - Data Circuit terminating;Equipment (DTE - DCE) interface for Short Message Service (SMS) and Cell Broadcast Service (CBS) ,介绍 at 的一些控制命令。

Gsm07.07 规范:着重介绍 at 的短信相关命令,可以说是 at sms 规范。

1.1.2.     Block 模式

Block 模式基本已经被 pdu 模式取代,没有具体研究

1.1.3.     Text 模式

Text 模式比较简单,但是支持的设备不是很全,而且对于中文似乎有些问题,在金笛的网站技术资料中似乎提到了一句不能实现中文。

AT CGMF=1<CR>

AT CGMS= 13605696031 ,129<CR>
>Hello World!<^Z>

1.1.4.     Pdu 模式

pdu 编码主要包括两个主要的部分,一是 pdu 串的整体数据格式,分别因为发送信息串和接收信息串而有区别,二是 pdu 中文本部分的编码,分别因为字符集而不同。

我们也可以这样来理解这个 pdu 编码的格式, sms 相当于一个协议栈,最简单的协议栈:

根据 gsm03.40 规范, sms 协议包括以下几层:

1、  SM-AL :应用层。这个部分就是数据部分。

2、  SM-TL :传输层。我们可以清楚的看到这里描述了主要的短信内容,包括发送号码,接收号码,信息类型,编码,数据报长度等等,这也是我们编程主要要面对的问题。

3、  SM-RL :中继层。这个指的是短信在网关之间中继需要的协议。

4、  SM-LL: 链路层。

从上述描述中我们可以清楚的看到,我们编程主要集中于传输层。

 

PDU 串的用户信息 (TP-UD) 段最大容量是 140 字节,所以在这三种编码方式下,可以发送的短消息的最大字符数分别是 160 140 70 。这里,将一个英文字母、一个汉字和一个数据字节都视为一个字符。

 

1.2. SMS 用户数据的编码方法

1.2.1.     英文 7 位编码

 

图片不能正确显示

这是
gsm 的默认编码方式

由于这样的移位,我们可以看到我们能发的最多英文字符等于: 140*8/7 = 160

1.2.2.     数据 8 位编码

8-bit 编码通常用于发送数据消息,比如图片和铃声等;

1.2.3.     中文 pdu 编码

发送中文时,必须用 UCS2 utf-16 )进行编码,最多可以发 140/2 70 个汉字。

UniCode 编码转换也比较简单,以中文为例,一个中文字符是两个字节,直接对高位字节和低位字节进行十六进制转换就可以了。如“欢迎”, UniCode 编码是 6B22 8FCE ,这同时也就是转换的结果,如果发送的串中有英文字符,那么在前面补全 00 ,以保证一个字符对应两个字节。

1.2.4.     Wap-push 中的中文编码

wap-push 短信的时候有些问题了,开始的时候也按照 Unicode 编码处理,总是失败,后来才发现,有个编码字段设为了 uft-8 ,所以在这种情况下,还是可以出现其他编码方式的。

 

1.3. 短信报头分析

1.3.1.     短信类型

详细请参考 gsm 0438 规范和 gsm0440 规范,里面有详细的关于各种短消息类型的描述。

sms 中到底支持多少种类型的短信,短信类型由什么进行控制,这是我们在这里需要着重介绍的问题。

在传输层来分,一共有六大短信类型: SMS-DELIVER SMS-DELIVER-REPORT SMS-SUBMIT

SMS-SUBMIT-REPORT SMS-STATUS-REPORT SMS-COMMAND ,这六种短信类型,由短信中心地址后的第一个字节的最低两位控制。

 

bit1

bit0

Message type

0

0

SMS-DELIVER (in the direction SC to MS)

0

0

SMS-DELIVER REPORT (in the direction MS to SC)

1

0

SMS-STATUS-REPORT (in the direction SC to MS)

1

0

SMS-COMMAND (in the direction MS to SC)

0

1

SMS-SUBMIT (in the direction MS to SC)

0

1

SMS-SUBMIT-REPORT (in the direction SC to MS)

1

1

Reserved

 

也就是说,每个短信在短信中心地址之后的第一个字节的最低两位是至关重要的。他决定了如何读这条短信(结合是发送的,还是接收的)

1.3.2.     地址编码

短信发送中都会涉及到短信地址的问题,他们的编码规则是一致的 , 简单来说就是 BCD8421编码

如: 08 91 683108501505F 0

08 :地址长度,(号码类型 + 号码长度) /2 的十六进制表示

91 :号码类型

683108501505F 0 :号码,实际号码应为: 8613805515500 ,号码处理方法为 , 如果为 +86 开始 , + 号去掉 , 然后判断是否为偶数 , 不是在末尾补 F, 然后将奇数位和偶数位互换

1.3.3.     TP-DCS( 数据编码格式 )

这个字节比较特殊,表明整个短信的字符编码,数据内容等信息。详细说明参考 gsm03.38 规范。

1.3.4.     第一个字节

Pdu 编码的第一个字节比较有意思,这个字节会根据六种不同的短信按位有不同的意思,拿句专业一点的话来说,叫 bitmask. 用图来大概描述一下,详细参考 gsm0340 9.2.3 段。

 

 

位数

MSG_Deliever

MSG_SUBMIT

7

TP_RP (回复地址)

TP_RP

6

TP_UDHI (数据报头)

TP_UDHI

5

TP_SRI (需要回复)

TP_SRR (请求回复)

4

 

TP_VPF( 时间格式 )

3

 

2

TP_MMS (多条短信标志, 1 为无, 0 为有)

TP_RD( 拒绝重复标志 )

1 0

TP_MTI (短信类型)

TP_MTI

常见值

04 ,正常收到, 44 ,有报头短信

11 ,正常发送, 51 ,有报头短信

1.3.5.     TP-PID (协议标识)

在这个里面还有一个字节比较特殊,就是协议标识。

一般都是 00 ,表示点到点的标准短信。

1.3.6.     超长短信

参考 gsm0340 9.2.3 .24TP_UD 部分,这个部分中间的一种情况就是描述超长短信的处理。

长短信关键涉及一个数据报头的问题,数据报头由“长度”和多个“数据元素”组成。

1.3.7.     Wap-push 短信

WAP 的推送协议中定义了服务指示( SI Service Indication )和服务加载( SL Service Load )两项服务,以给用户和网络运营者更多的选择。服务指示是将新信息的指示和相关的通用资源标识符( URI )推送给用户,由用户选择是立即处理信息还是以后处理。服务加载是将一项服务的 URI 推送给用户,然后客户端自动地使用 PULL 技术根据该 URI 启动服务。两种服务的区别在于用户是否介入推送信息的处理过程。 SL 对推送信息的处理对用户来说是透明的,而 SI 则在指示用户的同时,请用户对随后的处理做出选择。
PUSH
可以将某一站点或某一业务的链接通过短信发送到支持 WAP PUSH 功能的手机上,这样用户只需要阅读这条短信,打开短信中的链接,就可以直接访问业务了。因此, WAP PUSH 实现了短信和 WAP 业务的结合,节省了用户寻找业务的时间,方便用户直接找到并使用自己喜欢的业务。

Wap-push 短信的核心不同之处就在于:

1、  含有数据报头,也就是 TP_UDHI 位为 1 ,一般来说 pdu 的第一个字节发送时为 51 ,接收时为 44

2、  TP_DSC 字节不同,一般为 F5 ,表明字符集为 8 位,短信类型为 Class 1; 详细解释参看 gsm03.38 的第四章。

1.4. 编码示例

1.4.1.     发送信息的 PDU 串:

用手机写一条短信息,发送手机号码为 13605696031 ,信息内容为“ Hello World! ”。通过执行 AT CMGL=2 可以读出此条信息。

 

AT CMGL=2 { 读未发短信息 }
CMGL: 1,2,,24 {1 表示信息个数, 2 表示未发信息, 24 表示信息总容量 }
08 91 683108501505F0 11 00 0B 81 3106656930F1 0000FF 0B E8329BFD06DDDF723619
OK

 

下面分析这条信息:

 

08

短信息中心地址长度。(短信息中心号码类型 + 短信息中心号码长度 /2 的十六进制表示)

91

短信息中心号码类型, 91 TON/NPI TON/NPI 遵守 International/E.164 标准,指在号码前需加‘+’号 ; 此外还可有其他数值,但 91 最常用。

683108501505F 0

短信息中心号码,是所使用的服务中心地址。由于位置上略有处理,实际号码应为: 8613805515500( 字母 F 意指长度减 1), 这是作者所在地 GSM 短信息中心的号码。 ( 号码处理方法为 , 如果为 +86 开始 , + 号去掉 , 然后判断是否为偶数 , 不是在末尾补 F, 然后将奇数位和偶数位互换 )

11

文件头字节 (header byte, 是一种 bitmask) 。这里 11 指正常地发送短信息。

00

信息参考号。( TP-MR

0D

被叫号码长度。被叫号码长度的十六进制表示。

81

被叫号码类型。

3106656930F 1

被叫号码,也经过了移位处理,实际号码为 13605696031

00

协议标识 (TP-PID), 是普通 GSM 类型,点到点方式

00

用户信息编码方式 (TP-DCS) , 7-bit 编码( 08 UCS2 编码)

FF

有效期 (TP-VP), 短信的有效时间

0B

短信息长度

E8329BFD06DDDF723619

短信息内容“ Hello World! ”。

1.4.2.     接受信息的 PDU

读取以上发送出来的

分享到:
评论
1 楼 lydawen 2011-11-04  
对wappush协议有了深入的了解。三大运营商主要是在CMPP上添加了计费信息,体现了中国特色,非得把一个本来简单的协议弄得复杂,好像协议都是自己研究出来的一样。三大运营商的研究院,其实大部分都是“研究院”

相关推荐

Global site tag (gtag.js) - Google Analytics