RSS订阅 | 匿名投稿
您的位置:网站首页 > 单元 > 正文

delphi 移动短信接口(cmpp 2.0)

作者:admin 来源: 日期:2013/1/24 12:55:10 人气: 标签:短信接口

// delphi 移动短信接口(cmpp 2.0)
//
 
unit untYiDongInterface;
 
interface
 
uses
 SysUtils, untSocket, IdGlobal, MessageDigest_5, Types;
 
const
{$REGION 'Command_Id定义'}
CMPP_CONNECT = $00000001; // 请求连接
CMPP_CONNECT_RESP = $80000001; // 请求连接应答
CMPP_TERMINATE = $00000002; // 终止连接
CMPP_TERMINATE_RESP = $80000002; // 终止连接应答
CMPP_SUBMIT = $00000004; // 提交短信
CMPP_SUBMIT_RESP = $80000004; // 提交短信应答
CMPP_DELIVER = $00000005; // 短信下发
CMPP_DELIVER_RESP = $80000005; // 下发短信应答
CMPP_QUERY = $00000006; // 发送短信状态查询
CMPP_QUERY_RESP = $80000006; // 发送短信状态查询应答
CMPP_CANCEL = $00000007; // 删除短信
CMPP_CANCEL_RESP = $80000007; // 删除短信应答
CMPP_ACTIVE_TEST = $00000008; // 激活测试
CMPP_ACTIVE_TEST_RESP = $80000008; // 激活测试应答
CMPP_FWD = $00000009; // 消息前转
CMPP_FWD_RESP = $80000009; // 消息前转应答
CMPP_MT_ROUTE = $00000010; // MT路由请求
CMPP_MT_ROUTE_RESP = $80000010; // MT路由请求应答
CMPP_MO_ROUTE = $00000011; // MO路由请求
CMPP_MO_ROUTE_RESP = $80000011; // MO路由请求应答
CMPP_GET_ROUTE = $00000012; // 获取路由请求
CMPP_GET_ROUTE_RESP = $80000012; // 获取路由请求应答
CMPP_MT_ROUTE_UPDATE = $00000013; // MT路由更新
CMPP_MT_ROUTE_UPDATE_RESP = $80000013; // MT路由更新应答
CMPP_MO_ROUTE_UPDATE = $00000014; // MO路由更新
CMPP_MO_ROUTE_UPDATE_RESP = $80000014; // MO路由更新应答
CMPP_PUSH_MT_ROUTE_UPDATE = $00000015; // MT路由更新
CMPP_PUSH_MT_ROUTE_UPDATE_RESP = $80000015; // MT路由更新应答
CMPP_PUSH_MO_ROUTE_UPDATE = $00000016; // MO路由更新
CMPP_PUSH_MO_ROUTE_UPDATE_RESP = $80000016; // MO路由更新应答
{$ENDREGION}
 const_SP_Id = 'HHJC'; // SP的企业代码
const_shared_secret = ''; // 由中国移动与源地址实体事先商定
const_Version = 11; // 双方协商的版本号(高位4bit表示主版本号,低位4bit表示次版本号 www.delphitop.com
 
type
{$REGION '缓存定义'}
TByte21 = array [0 .. 20] of Byte;
 TByte8 = array [0 .. 7] of Byte;
 TChar21 = array [0 .. 20] of AnsiChar;
 TChar10 = array [0 .. 9] of AnsiChar;
 TChar140 = array [0 .. 139] of AnsiChar;
 TChar8 = array [0 .. 7] of AnsiChar;
 TChar6 = array [0 .. 5] of AnsiChar;
 TChar16 = array [0 .. 15] of AnsiChar;
 TChar2 = array [0 .. 1] of AnsiChar;
 TChar17 = array [0 .. 16] of AnsiChar;
{$ENDREGION}
{$REGION '公用消息头定义'}
{
Total_Length 4 Unsigned Integer 消息总长度(含消息头及消息体)
Command_Id 4 Unsigned Integer 命令或响应类型
Sequence_Id 4 Unsigned Integer 消息流水号,顺序累加,步长为1,循环使用(一对请求和应答消息的流水号必须相同)
}
TMsgHeader = packed record
 Total_Length: Cardinal;
 Command_Id: Cardinal;
 Sequence_Id: Cardinal;
 end;
{$ENDREGION}
{$REGION 'SP请求连接到ISMG(CMPP_CONNECT)操作'}
{
Source_Addr 6 Octet String 源地址,此处为SP_Id,即SP的企业代码。
AuthenticatorSource 16 Octet String 用于鉴别源地址。其值通过单向MD5 hash计算得出,表示如下:
AuthenticatorSource =
MD5(Source_Addr+9 字节的0 +shared secret+timestamp)
Shared secret 由中国移动与源地址实体事先商定,timestamp格式为:MMDDHHMMSS,即月日时分秒,10位。
Version 1 Unsigned Integer 双方协商的版本号(高位4bit表示主版本号,低位4bit表示次版本号)
Timestamp 4 Unsigned Integer 时间戳的明文,由客户端产生,格式为MMDDHHMMSS,即月日时分秒,10位数字的整型,右对齐 。
}
TConnect = packed record
 Source_Addr: TChar6;
 AuthenticatorSource: TChar16;
 Version: Byte;
 Timestamp: Cardinal;
 end;
 
TConnectMsg = packed record
 Head: TMsgHeader;
 Body: TConnect;
 end;
{$ENDREGION}
{$REGION 'SP向ISMG提交短信(CMPP_SUBMIT)操作'}
{
Msg_Id 8 Unsigned Integer 信息标识,由SP侧短信网关本身产生,本处填空。
Pk_total 1 Unsigned Integer 相同Msg_Id的信息总条数,从1开始
Pk_number 1 Unsigned Integer 相同Msg_Id的信息序号,从1开始
Registered_Delivery 1 Unsigned Integer 是否要求返回状态确认报告:
0:不需要
1:需要
2:产生SMC话单
 (该类型短信仅供网关计费使用,不发送给目的终端)
Msg_level 1 Unsigned Integer 信息级别
Service_Id 10 Octet String 业务类型,是数字、字母和符号的组合。
Fee_UserType 1 Unsigned Integer 计费用户类型字段
0:对目的终端MSISDN计费;
1:对源终端MSISDN计费;
2:对SP计费;
3:表示本字段无效,对谁计费参见Fee_terminal_Id字段。
Fee_terminal_Id 21 Unsigned Integer 被计费用户的号码(如本字节填空,则表示本字段无效,对谁计费参见Fee_UserType字段,
本字段与Fee_UserType字段互斥)
TP_pId 1 Unsigned Integer GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.9
TP_udhi 1 Unsigned Integer GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.23,仅使用1位,右对齐
Msg_Fmt 1 Unsigned Integer 信息格式
0:ASCII串
3:短信写卡操作
4:二进制信息
8:UCS2编码
 15:含GB汉字 。。。。。。
Msg_src 6 Octet String 信息内容来源(SP_Id)
FeeType 2 Octet String 资费类别
01:对“计费用户号码”免费
02:对“计费用户号码”按条计信息费
03:对“计费用户号码”按包月收取信息费
04:对“计费用户号码”的信息费封顶
05:对“计费用户号码”的收费是由SP实现
FeeCode 6 Octet String 资费代码(以分为单位)
ValId_Time 17 Octet String 存活有效期,格式遵循SMPP3.3协议
At_Time 17 Octet String 定时发送时间,格式遵循SMPP3.3协议
Src_Id 21 Octet String 源号码
SP的服务代码或前缀为服务代码的长号码, 网关将该号码完整的填到SMPP协议Submit_SM消息相应的source_addr字段,
该号码最终在用户手机上显示为短消息的主叫号码
DestUsr_tl 1 Unsigned Integer 接收信息的用户数量(小于100个用户)
Dest_terminal_Id 21*DestUsr_tl Octet String 接收短信的MSISDN号码
Msg_Length 1 Unsigned Integer 信息长度(Msg_Fmt值为0时:<160个字节;其它<=140个字节)
Msg_Content Msg_length Octet String 信息内容
Reserve 8 Octet String 保留
}
TSubmit = packed record
 Msg_Id: TByte8;
 Pk_total: Byte;
 Pk_number: Byte;
 Registered_Delivery: Byte;
 Msg_level: Byte;
 Service_Id: TChar10;
 Fee_UserType: Byte;
 Fee_terminal_Id: TByte21;
 TP_pId: Byte;
 TP_udhi: Byte;
 Msg_Fmt: Byte;
 Msg_src: TChar6;
 FeeType: TChar2;
 FeeCode: TChar6;
 ValId_Time: TChar17;
 At_Time: TChar17;
 Src_Id: TChar21;
 DestUsr_tl: Byte;
 Dest_terminal_Id: TByte21;
 Msg_Length: Byte;
 Msg_Content: TChar140;
 Reserve: TChar8;
 end;
 
TSubmitMsg = packed record
 Head: TMsgHeader;
 Body: TSubmit;
 end;
{$ENDREGION}
{$REGION 'ISMG向SP送交短信(CMPP_DELIVER)操作'}
{
Msg_Id 8 Unsigned Integer 信息标识
生成算法如下:
采用64位(8字节)的整数:
时间(格式为MMDDHHMMSS,即月日时分秒):bit64~bit39,其中
bit64~bit61:月份的二进制表示;
bit60~bit56:日的二进制表示;
bit55~bit51:小时的二进制表示;
bit50~bit45:分的二进制表示;
bit44~bit39:秒的二进制表示;
短信网关代码:bit38~bit17,把短信网关的代码转换为整数填写到该字段中。
序列号:bit16~bit1,顺序增加,步长为1,循环使用。
各部分如不能填满,左补零,右对齐。
Dest_Id 21 Octet String 目的号码
SP的服务代码,一般4--6位,或者是前缀为服务代码的长号码;该号码是手机用户短消息的被叫号码。
Service_Id 10 Octet String 业务类型,是数字、字母和符号的组合。
TP_pid 1 Unsigned Integer GSM协议类型。详细解释请参考GSM03.40中的9.2.3.9
TP_udhi 1 Unsigned Integer GSM协议类型。详细解释请参考GSM03.40中的9.2.3.23,仅使用1位,右对齐
Msg_Fmt 1 Unsigned Integer 信息格式
0:ASCII串
3:短信写卡操作
4:二进制信息
8:UCS2编码
 15:含GB汉字
Src_terminal_Id 21 Octet String 源终端MSISDN号码(状态报告时填为CMPP_SUBMIT消息的目的终端号码)
Registered_Delivery 1 Unsigned Integer 是否为状态报告
0:非状态报告
1:状态报告
Msg_Length 1 Unsigned Integer 消息长度
Msg_Content Msg_length Octet String 消息内容
Reserved 8 Octet String 保留项
}
TDeliver = packed record
 Msg_Id: TByte8;
 Dest_Id: TChar21;
 Service_Id: TChar10;
 TP_pId: Byte;
 TP_udhi: Byte;
 Msg_Fmt: Byte;
 Src_terminal_Id: TChar21;
 Registered_Delivery: Byte;
 Msg_Length: Byte;
 Msg_Content: TChar140;
 Reserved: TChar8;
 end;
 
TDeliverMsg = packed record
 Head: TMsgHeader;
 Body: TDeliver;
 end;
{$ENDREGION}
{$REGION '连接方法'}
 
function Connect(Sequence_Id, Timestamp: Cardinal;
 SP_Id, AuthenticatorSource: AnsiString; Version: Byte): Boolean; // 连接
{
Source_Addr 6 Octet String 源地址,此处为SP_Id,即SP的企业代码。
AuthenticatorSource 16 Octet String 用于鉴别源地址。其值通过单向MD5 hash计算得出,表示如下:
AuthenticatorSource =
MD5(Source_Addr+9 字节的0 +shared secret+timestamp)
Shared secret 由中国移动与源地址实体事先商定,timestamp格式为:MMDDHHMMSS,即月日时分秒,10位。
Version 1 Unsigned Integer 双方协商的版本号(高位4bit表示主版本号,低位4bit表示次版本号)
Timestamp 4 Unsigned Integer 时间戳的明文,由客户端产生,格式为MMDDHHMMSS,即月日时分秒,10位数字的整型,右对齐 。
}
{$ENDREGION}
{$REGION '发送方法'}
procedure Send(Sequence_Id: Cardinal; Pk_total, Pk_number, Registered_Delivery,
 Msg_level, Fee_UserType, TP_pId, TP_udhi, Msg_Fmt, DestUsr_tl,
 Msg_Length: Byte; Service_Id, Msg_src, FeeType, FeeCode, ValId_Time, At_Time,
 Src_Id, Msg_Content: AnsiString; Dest_terminal_Id: AnsiString);
{
Msg_Id 8 Unsigned Integer 信息标识,由SP侧短信网关本身产生,本处填空。
Pk_total 1 Unsigned Integer 相同Msg_Id的信息总条数,从1开始
Pk_number 1 Unsigned Integer 相同Msg_Id的信息序号,从1开始
Registered_Delivery 1 Unsigned Integer 是否要求返回状态确认报告:
0:不需要
1:需要
2:产生SMC话单
 (该类型短信仅供网关计费使用,不发送给目的终端)
Msg_level 1 Unsigned Integer 信息级别
Service_Id 10 Octet String 业务类型,是数字、字母和符号的组合。
Fee_UserType 1 Unsigned Integer 计费用户类型字段
0:对目的终端MSISDN计费;
1:对源终端MSISDN计费;
2:对SP计费;
3:表示本字段无效,对谁计费参见Fee_terminal_Id字段。
Fee_terminal_Id 21 Unsigned Integer 被计费用户的号码(如本字节填空,则表示本字段无效,对谁计费参见Fee_UserType字段,本字段与Fee_UserType字段互斥)
TP_pId 1 Unsigned Integer GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.9
TP_udhi 1 Unsigned Integer GSM协议类型。详细是解释请参考GSM03.40中的9.2.3.23,仅使用1位,右对齐
Msg_Fmt 1 Unsigned Integer 信息格式
0:ASCII串
3:短信写卡操作
4:二进制信息
8:UCS2编码
 15:含GB汉字 。。。。。。
Msg_src 6 Octet String 信息内容来源(SP_Id)
FeeType 2 Octet String 资费类别
01:对“计费用户号码”免费
02:对“计费用户号码”按条计信息费
03:对“计费用户号码”按包月收取信息费
04:对“计费用户号码”的信息费封顶
05:对“计费用户号码”的收费是由SP实现
FeeCode 6 Octet String 资费代码(以分为单位)
ValId_Time 17 Octet String 存活有效期,格式遵循SMPP3.3协议
At_Time 17 Octet String 定时发送时间,格式遵循SMPP3.3协议
Src_Id 21 Octet String 源号码
SP的服务代码或前缀为服务代码的长号码, 网关将该号码完整的填到SMPP协议Submit_SM消息相应的source_addr字段,该号码最终在用户手机上显示为短消息的主叫号码
DestUsr_tl 1 Unsigned Integer 接收信息的用户数量(小于100个用户)
Dest_terminal_Id 21*DestUsr_tl Octet String 接收短信的MSISDN号码
Msg_Length 1 Unsigned Integer 信息长度(Msg_Fmt值为0时:<160个字节;其它<=140个字节)
Msg_Content Msg_length Octet String 信息内容
Reserve 8 Octet String 保留
 
}
{$ENDREGION}
{$REGION '接收方法'}
procedure Accept(var Msg_Id: AnsiString; var Dest_Id, Service_Id, Src_terminal_Id,
 Msg_Content: AnsiString; var TP_pId, TP_udhi, Msg_Fmt, Registered_Delivery,
 Msg_Length: Byte);
{
Msg_Id 8 Unsigned Integer 信息标识
生成算法如下:
采用64位(8字节)的整数:
时间(格式为MMDDHHMMSS,即月日时分秒):bit64~bit39,其中
bit64~bit61:月份的二进制表示;
bit60~bit56:日的二进制表示;
bit55~bit51:小时的二进制表示;
bit50~bit45:分的二进制表示;
bit44~bit39:秒的二进制表示;
短信网关代码:bit38~bit17,把短信网关的代码转换为整数填写到该字段中。
序列号:bit16~bit1,顺序增加,步长为1,循环使用。
各部分如不能填满,左补零,右对齐。
Dest_Id 21 Octet String 目的号码
SP的服务代码,一般4--6位,或者是前缀为服务代码的长号码;该号码是手机用户短消息的被叫号码。
Service_Id 10 Octet String 业务类型,是数字、字母和符号的组合。
TP_pid 1 Unsigned Integer GSM协议类型。详细解释请参考GSM03.40中的9.2.3.9
TP_udhi 1 Unsigned Integer GSM协议类型。详细解释请参考GSM03.40中的9.2.3.23,仅使用1位,右对齐
Msg_Fmt 1 Unsigned Integer 信息格式
0:ASCII串
3:短信写卡操作
4:二进制信息
8:UCS2编码
 15:含GB汉字
Src_terminal_Id 21 Octet String 源终端MSISDN号码(状态报告时填为CMPP_SUBMIT消息的目的终端号码)
Registered_Delivery 1 Unsigned Integer 是否为状态报告
0:非状态报告
1:状态报告
Msg_Length 1 Unsigned Integer 消息长度
Msg_Content Msg_length Octet String 消息内容
Reserved 8 Octet String 保留项
}
{$ENDREGION}
 
{$REGION '消息流水号'}
var
 g_Sequence_Id: Cardinal = 0;
function GetSequence_Id: Integer; // 消息流水号,顺序累加,步长为1,循环使用(一对请求和应答消息的流水号必须相同)
{$ENDREGION}
 
function MD5(value: AnsiString): string; // MD5加密
 
implementation
 
function MD5(value: AnsiString): string;
var
 m: IMD5;
begin
 m := GetMD5;
 m.Init;
 m.Update(TByteDynArray(RawByteString(value)), Length(value));
 Result := LowerCase(m.AsString);
end;
 
function GetSequence_Id: Integer;
begin
 if g_Sequence_Id = 4294967295 then
 g_Sequence_Id := 0;
 g_Sequence_Id := g_Sequence_Id + 1;
 Result := g_Sequence_Id;
end;
 
procedure Accept(var Msg_Id: AnsiString; var Dest_Id, Service_Id, Src_terminal_Id,
 Msg_Content: AnsiString; var TP_pId, TP_udhi, Msg_Fmt, Registered_Delivery,
 Msg_Length: Byte);
var
 Head: TMsgHeader;
 Body: TDeliver;
 Msg: TDeliverMsg;
 buf: TIdBytes;
begin
 // 初始化
buf := nil;
 FillChar(Head, SizeOf(Head), '');
 FillChar(Body, SizeOf(Body), '');
 FillChar(Msg, SizeOf(Msg), '');
 // 接收
if frmSocket.Connect then
 begin
 frmSocket.tcp.IOHandler.ReadBytes(buf, SizeOf(Msg), false);
 BytesToRaw(buf, Msg, SizeOf(Msg));
 Head := Msg.Head;
 Body := Msg.Body;
 // 解析
if Head.Command_Id = CMPP_DELIVER then
 begin
 SetLength(Msg_Id, SizeOf(Body.Msg_Id) + 1);
 Move(Body.Msg_Id, Msg_Id[1], SizeOf(Body.Msg_Id));
 SetLength(Dest_Id, SizeOf(Body.Dest_Id) + 1);
 Move(Body.Dest_Id, Dest_Id[1], SizeOf(Body.Dest_Id));
 SetLength(Service_Id, SizeOf(Body.Service_Id) + 1);
 Move(Body.Service_Id, Service_Id[1], SizeOf(Body.Service_Id));
 TP_pId := Body.TP_pId;
 TP_udhi := Body.TP_udhi;
 Msg_Fmt := Body.Msg_Fmt;
 SetLength(Src_terminal_Id, SizeOf(Body.Src_terminal_Id) + 1);
 Move(Body.Src_terminal_Id, Src_terminal_Id[1], SizeOf(Body.Src_terminal_Id));
 Registered_Delivery := Body.Registered_Delivery;
 Msg_Length := Body.Msg_Length;
 SetLength(Msg_Content, SizeOf(Body.Msg_Content) + 1);
 Move(Body.Msg_Content, Msg_Content[1], SizeOf(Body.Msg_Content));
 end;
 end;
end;
 
procedure Send(Sequence_Id: Cardinal; Pk_total, Pk_number, Registered_Delivery,
 Msg_level, Fee_UserType, TP_pId, TP_udhi, Msg_Fmt, DestUsr_tl,
 Msg_Length: Byte; Service_Id, Msg_src, FeeType, FeeCode, ValId_Time, At_Time,
 Src_Id, Msg_Content: AnsiString; Dest_terminal_Id: AnsiString);
var
 Head: TMsgHeader;
 Body: TSubmit;
 Msg: TSubmitMsg;
 buf: TIdBytes;
begin
 // 初始化
buf := nil;
 FillChar(Head, SizeOf(Head), '');
 FillChar(Body, SizeOf(Body), '');
 FillChar(Msg, SizeOf(Msg), '');
 if frmSocket.Connect then
 begin
 // 消息头
Head.Total_Length := SizeOf(Head) + SizeOf(Body);
 Head.Command_Id := CMPP_SUBMIT;
 Head.Sequence_Id := Sequence_Id;
 // 消息体
Body.Pk_total := Pk_total;
 Body.Pk_number := Pk_number;
 Body.Registered_Delivery := Registered_Delivery;
 Body.Msg_level := Msg_level;
 StrPCopy(Body.Service_Id, Service_Id);
 Body.Fee_UserType := Fee_UserType;
 Body.TP_pId := TP_pId;
 Body.TP_udhi := TP_udhi;
 Body.Msg_Fmt := Msg_Fmt;
 StrPCopy(Body.Msg_src, Msg_src);
 StrPCopy(Body.FeeType, FeeType);
 StrPCopy(Body.FeeCode, FeeCode);
 StrPCopy(Body.ValId_Time, ValId_Time);
 StrPCopy(Body.At_Time, At_Time);
 StrPCopy(Body.Src_Id, Src_Id);
 Body.DestUsr_tl := DestUsr_tl;
 Move(Dest_terminal_Id[1], Body.Dest_terminal_Id, Length(Dest_terminal_Id));
 Body.Msg_Length := Msg_Length;
 StrPCopy(Body.Msg_Content, Msg_Content);
 // 消息
Msg.Head := Head;
 Msg.Body := Body;
 // 发送
buf := RawToBytes(Msg, SizeOf(Msg));
 frmSocket.tcp.IOHandler.Write(buf);
 end;
end;
 
function Connect(Sequence_Id, Timestamp: Cardinal;
 SP_Id, AuthenticatorSource: AnsiString; Version: Byte): Boolean;
var
 Head: TMsgHeader;
 Body: TConnect;
 Msg: TConnectMsg;
 buf: TIdBytes;
begin
 // 初始化
buf := nil;
 FillChar(Head, SizeOf(Head), '');
 FillChar(Body, SizeOf(Body), '');
 FillChar(Msg, SizeOf(Msg), '');
 Result := frmSocket.Connect;
 if Result then
 begin
 // 消息头
Head.Total_Length := SizeOf(TConnectMsg);
 Head.Command_Id := CMPP_CONNECT;
 Head.Sequence_Id := Sequence_Id;
 // 消息体
StrPCopy(Body.Source_Addr, SP_Id);
 StrPCopy(Body.AuthenticatorSource, AuthenticatorSource);
 Body.Version := Version;
 Body.Timestamp := Timestamp;
 // 消息
Msg.Head := Head;
 Msg.Body := Body;
 // 发送
buf := RawToBytes(Msg, SizeOf(Msg));
 frmSocket.tcp.IOHandler.Write(buf);
 end;
end;
 
end.

读完这篇文章后,您心情如何?
0
0
0
0
0
0
0
0
本文网址: