最近要增加短信平台对移动CMPP3协议的支持,所以就研究了下他的实现。所谓的CMPP就是中国移动通信互联网短信网关接口协议。
CMPP 协议以TCP/IP 作为底层通信承载,所以开发这块需要对TCP/IP网络编程要有一定的了解。
原理:个人理解就是双方建立以什么方式来通信,就好比信是暗号写的,只有双方看的懂。
本文主要针对于长连接形式发送短信为例,而我们编写程序也只用编写在C/S架构的通讯过程中的C,然后根据服务商提供的帐号、参数经行测试。
下图是长连接的流程图。
一、实现协议步骤:
1、建立SOKCET,启动一个线程,发送数据。
2、进行链路检查,判断服务端通信是否正常等等。
3、启动接收socket数据的线程。
二、协议代码实现:
1、协议基本类型如下:
Unsigned Integer |
无符号整数 |
Integer |
整数,可为正整数、负整数或零 |
Octet String |
定长字符串,位数不足时,如果左补 0 则补ASCII 表示的零以填充,如果右补 0 则补二进制的零以表示字符串的结束符 |
2、消息结构:
1)消息头(所有消息公共包头)PS:注意红色的部分是所有消息的公共头
2)和消息体
三、接下来就是说说如何封装CMPP3的消息格式了,取几个谈谈就行了,原理都差不多。
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import org.apache.log4j.Logger; //totalLength 消息总长度 //commandID命令消息类型 //sequenceID消息流水号码,顺序累加,步长为1,循环使用(一队请求和应答消息的流水号必须相同) //Unsigned Integer 无符号整型 //Integer 整数,可为正整数、负整数、零 //Octet String 定长字符串,位数不足时,如果左补0则补ASCII表示的0以填充,如果右补0则补二进制的零表示字符串的结束符 public class MsgHead { private Logger logger = Logger.getLogger(MsgHead.class); private int totalLength; // unsigned Integer; private int commandID; // unsigned Integer; private int sequenceID; // unsigned Integer; public byte[] toByteArray() { ByteArrayOutputStream bous = new ByteArrayOutputStream(); DataOutputStream dous = new DataOutputStream(bous); try { dous.writeInt(getTotalLength()); dous.writeInt(this.getCommandID()); dous.writeInt(this.getSequenceID()); dous.close(); return bous.toByteArray(); } catch (Exception e) { if (dous != null) try { dous.close(); } catch (Exception ee) { } logger.error("封装CMPP消息头二进制数组失败!"); return null; } } }
代码片段:
import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import org.apache.log4j.Logger; import common.msg.util.MsgUtils; /** * sp请求连接到ISMG消息体定义CMPP_CONNECT操作的目的是向ISMG注册为一个合法SP身份, * 若注册成功后建立了应用层的连接,此后SP可以通过此ISMG接收和发送短信。 Source_Addr:Octet String * 源地址,此处为SP_id,即SP的企业代码 AuthenticatorSource:Octet String 用于鉴别源地址,其值通过单向MD5 * hash计算得出,表示如下; * AuthenticatorSource=MD5(source_addr+9个字节的null+secret+timestamp) * Version:unsigned Integer 双方协商的版本号,对3.0的版本,高4BIT为3,低4位为0 */ public class MsgConnect extends MsgHead { private static Logger logger = Logger.getLogger(MsgConnect.class); private String sourceAddr;// 源地址,此处为spID; private byte[] authenticatorSource;// 用于鉴别源地址 private byte version; private String timeStamp; public byte[] toByteArray() { ByteArrayOutputStream bous = new ByteArrayOutputStream(); DataOutputStream dous = new DataOutputStream(bous); try { dous.writeInt(this.getTotalLength()); dous.writeInt(this.getCommandID()); dous.writeInt(this.getSequenceID()); MsgUtils.writeString(dous, this.getSourceAddr(), 6,"US-ASCII"); dous.write(this.getAuthenticatorSource()); dous.writeByte(this.getVersion()); dous.writeInt(Integer.parseInt(getTimeStamp())); bous.close(); dous.close(); return bous.toByteArray(); } catch (Exception e) { if (bous != null) try { bous.close(); } catch (Exception ee) { } if (dous != null) try { dous.close(); } catch (Exception ee) { } e.printStackTrace(); logger.error("封装链接二进制数组失败。"); return null; } } }
代码片段:
import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import org.apache.log4j.Logger; import common.msg.util.MsgUtils; public class MsgSubmit extends MsgHead { private static Logger logger = Logger.getLogger(MsgSubmit.class); private long msgId = 0;// 信息标识,8个字节的unsigned为空 private byte pkTotal = 0x01;// 相同的msgID信息的总条数,从1开始,本业务填写1 private byte pkNumber = 0x01;// 系统MSGID的信息序号,从1开始,本业务只填写1 private byte registeredDelivery = 0x01; // 是否要求返回状态确认报告0不需要,1需要; private byte msgLevel = 0x01; private String serviceId = ""; // MSC4310508,业务标识是数字、字母、符号的组合 // 计费类型0:对目的终端MSISDN计费,1对源终端MSISDN计费,2对SP计费,3表示本字段无效 private byte feeUserType = 0x01;// 上线的确认此内容 private String feeTerminalId = "";// 被计费的号码,当feeUserType为3时有效 private byte feeTerminalType = 0x00;// 被计费用户的号码类型,0真实,1伪号码 private byte tpPId = 0x00; private byte tpUdhi = 0x00; // 0ASCII码字符串,3短信写卡操作,4二进制信息,8UCS2编码,15含GB汉字 private byte msgFmt = 0x0F; private String msgSrc = "";// 信息内容来源SPID; // 01:对“计费用户号码”免费,02:对“计费用户号码”按条计信息费 // 03:对“被计费号码包月计费,04:对被计费号码封顶,05:对被计费号码是由SP实现; private String feeType = "00";// 默认按条 private String feeCode = "000000"; private String validTime = "";// 存或有效期限,17位长度,暂时不支持此功能 private String atTime = "";// 定时发送时间,17位长度,暂时不支持此功能 private String srcId = "";// 源号码,用户手机显示的号码 private byte destUsrTl = 0x01;// 接受信息的用户数量(群发) private String destTerminalId = "";// 接受短信的号码 private byte destTerminalType = 0x00;// 真实号码 private byte msgLength;// 消息长度,小于或等于140字节 private byte[] msgContent;// 信息内容; private String linkID = "";// 点播业务使用,非点播业务则不使用 public byte[] toByteArray(String code) { ByteArrayOutputStream bous = new ByteArrayOutputStream(); DataOutputStream dous = new DataOutputStream(bous); try { dous.writeInt(this.getTotalLength()); dous.writeInt(this.getCommandID()); dous.writeInt(this.getSequenceID()); dous.writeLong(this.getMsgId());// Msg_Id 信息标识,由SP接入的短信网关本身产生,本处填空 dous.writeByte(this.getPkTotal());// Pk_total 相同Msg_Id的信息总条数 dous.writeByte(this.getPkNumber());// Pk_number 相同Msg_Id的信息序号,从1开始 dous.writeByte(this.getRegisteredDelivery());// Registered_Delivery // 是否要求返回状态确认报告 dous.writeByte(this.getMsgLevel());// Msg_level 信息级别 MsgUtils.writeString(dous, this.getServiceId(), 10, code);// Service_Id // 业务标识,是数字、字母和符号的组合。 dous.writeByte(this.getFeeUserType());// Fee_UserType 计费用户类型字段 // 0:对目的终端MSISDN计费;1:对源终端MSISDN计费;2:对SP计费;3:表示本字段无效,对谁计费参见Fee_terminal_Id字段。 MsgUtils.writeString(dous, this.getFeeTerminalId(), 32, code);// Fee_terminal_Id // 被计费用户的号码 dous.writeByte(this.getFeeTerminalType());// Fee_terminal_type // 被计费用户的号码类型,0:真实号码;1:伪码 dous.writeByte(this.getTpPId()); dous.writeByte(this.getTpUdhi()); dous.writeByte(this.getMsgFmt()); MsgUtils.writeString(dous, this.getMsgSrc(), 6, code);// Msg_src // 信息内容来源(SP_Id) MsgUtils.writeString(dous, this.getFeeType(), 2, code);// FeeType // 资费类别 MsgUtils.writeString(dous, this.getFeeCode(), 6, code); MsgUtils.writeString(dous, this.getValidTime(), 17, code);// 存活有效期 MsgUtils.writeString(dous, this.getAtTime(), 17, code);// 定时发送时间 MsgUtils.writeString(dous, this.getSrcId(), 21, code);// Src_Id // spCode dous.writeByte(this.getDestUsrTl()); MsgUtils.writeString(dous, this.getDestTerminalId(), 32, code); dous.writeByte(this.getDestTerminalType());// Dest_terminal_type // 接收短信的用户的号码类型,0:真实号码;1:伪码 dous.writeByte(this.getMsgLength()); dous.write(this.getMsgContent()); MsgUtils.writeString(dous, this.getLinkID(), 20,code); bous.close(); dous.close(); return bous.toByteArray(); } catch (Exception e) { if (bous != null) try { bous.close(); } catch (Exception ee) { } if (dous != null) try { dous.close(); } catch (Exception ee) { } logger.error("封装短信发送二进制数组失败。"); e.printStackTrace(); return null; } }
其实这些实现挺简单的,网上也有很多类似代码,主要要明确的一点就是,客户端和服务端的通信流程和消息长度,多看协议文档。懂了原理,实现起来很简单。
最后附CMPP3协议文档。
相关推荐
Java CMPP3.0协议实现是一项针对中国移动通信网络服务提供商(SP)端网关开发的关键技术。CMPP(China Mobile Packet Protocol)是中国移动为SP提供的基于TCP/IP的数据传输协议,主要用于短信、彩信等业务的传输。CMPP...
6. **测试与调试**:在开发过程中,可以使用_cmpp3.0_文件中的样例数据进行单元测试,模拟SMSC的响应,确保协议实现的正确性。此外,日志记录也是必不可少的,它可以帮助开发者在出现问题时快速定位和解决问题。 7....
Java实现CMPP协议开发代码主要涉及的是中国移动通信的CMPP(China Mobile Packet Protocol)协议,该协议主要用于短信中心(SMSC)与短信网关(SP)之间的数据传输,包括发送短消息、接收短消息以及相关的控制功能。...
CMPP协议的简单实现(只实现connect和submit,java实现),个人闲来练手所写,在公司实际环境下测试通过,并注明详细注释,希望能对刚接触CMPP的人有所帮助,有问题可以联系qq66921494
CMPP(China Mobile Short Message Peer-to-Peer)是中国移动推出的一种用于SP(Service Provider)与移动短信...开发者在实现基于CMPP的系统时,需要理解协议细节,合理设计系统架构,以保证服务的稳定性和高效率。
在Java环境中实现CMPP2.0协议,可以让我们更好地理解和控制短信服务的流程。 一、CMPP2.0协议简介 CMPP2.0协议是基于TCP/IP通信协议栈的,它定义了SP和SCP之间的数据交互格式和规则。协议主要包括连接建立、消息...
3. **编码与解码**:CMPP协议中的数据通常使用GBK或UTF-8编码,你需要实现编码和解码的函数,确保数据正确无误地在网络中传输。 4. **消息处理**:根据不同的命令ID,解析和处理接收到的消息,如提交短信、接收短信...
在这个项目中,我们使用了C语言来实现一个基于中国移动CMPP3协议的短信网关。CMPP(China Mobile Peer to Peer)是中国移动为SP(Service Provider)提供的一个标准化接口,主要用于实现SP与移动运营商之间的数据...
3. **互联网短信网关(ISMG)与汇接网关(GNS)之间的接口协议**:这部分描述了ISMG与GNS之间如何建立连接、查询路由信息、更新路由配置等内容。 #### 三、缩略语及术语解释 - **ISMG (Internet Short Message ...
在本文中,我们将深入探讨CMPP2.0协议的核心概念、功能特性以及实现细节。 一、CMPP2.0协议概述 CMPP(China Mobile Peer to Peer)2.0协议是基于TCP/IP协议栈的,用于SP系统与移动网络之间的直接通信。它的主要...
在本资源中,包含的源码应该是实现了CMPP3.0协议的程序,能够帮助开发者快速接入中国移动的短信网关。 源码中的关键知识点主要包括以下几个方面: 1. **连接与断开**:CMPP_CONNECT和CMPP_TERMINATE是协议的基础...
中国移动的CMPP(China Mobile Packet Protocol)协议是用于短信服务的一种通信协议,主要应用于SP(Service Provider)...通过对给定的文件进行分析和改进,可以构建一个更完善的CMPP3协议实现,满足短信服务的需求。
【描述】"基于中国移动cmpp3协议开发的短信网关源码",意味着这个项目直接利用了CMPP3.0协议的特性,实现了短信的发送、接收和处理功能。短信网关是连接移动运营商网络和企业应用的关键组件,它允许应用程序通过标准...
3. 短信状态报告:ISMG可以通过CMPP2.0协议将短信状态报告传输到SP。 协议栈 CMPP2.0协议栈主要包括以下几层: 1. 物理层:定义了物理连接的接口和传输方式。 2. 数据链路层:定义了帧格式和错误检测机制。 3. ...
在Java中实现CMPP协议,我们需要理解其工作原理,掌握相关的Java网络编程和数据编码知识。 1. **CMPP协议基础** CMPP协议是三层结构的协议,包括连接层、消息层和应用层。连接层负责建立、维护和断开TCP连接;消息...
综上所述,"cmpp短信网关协议实现"涵盖了从理论到实践的多个方面,包括协议规范、Java实现、华为源码以及测试案例。通过深入理解和应用这些知识,开发者可以构建自己的短信服务系统,与中国移动的短信网关进行有效...
3. **消息类型**:CMPP协议定义了多种消息类型,包括CMPP_SUBMIT(提交短信)、CMPP_DELIVER(接收短信)、CMPP_QUERY(查询短信状态)、CMPP_CANCEL(取消发送短信)等。每种消息类型都有特定的字段和操作流程。 4...
《中国移动CMPP3.0协议详解》 中国移动通信集团为了高效、稳定地处理大量短消息服务(SMS)和彩信服务(MMS)业务,制定了CMPP(China Mobile Packet Protocol)协议,其中CMPP3.0是其最新的版本。本文将深入探讨...
中国移动通信互联短信网关接口协议,简称CMPP2.0,是中国移动为了实现高效、稳定、安全的短信服务而制定的一种通信协议。该协议是CMPP系列协议的一个重要版本,主要针对互联网与短信网关之间的通信,为互联网应用...
CMPP协议,全称为China Mobile Peer-to-Peer协议,是中国移动为实现SP(Service Provider)与SCP(Service Control Point)之间的高效、可靠的数据传输而制定的一套通信协议。该协议主要用于短信服务,包括发送、...