基于华为smproxy_20040730.jar的CMPP和SMPP的短信构造(支持长短信)
来源:互联网 发布:内核参数优化 编辑:程序博客网 时间:2024/05/29 10:33
网上有许多关于CMPP和SMPP的介绍,这里不重复说了,直接介绍短信的构造方法。
1、CMPP短信构造方法:
/** * 构造消息体 * msisdns:要发送的手机号码 * msgContent:消息内容 */private CMPPSubmitMessage[] productMsg(String[] msisdns, String msgContent);
如果是短短信(msgContent.length() <= 70),可以采用如下构造方法:
CMPPSubmitMessage msg = new CMPPSubmitMessage(1, 1, config.getRegistered_Delivery(), config.getMsg_level(), config.getService_Id(), config.getFee_UserType(), "", config.getTp_Pid(), config.getTp_Udhi(), config.getMsg_Fmt(), config.getMsg_Src(), config.getFee_Type(), config.getFee_Code(), null, null, config.getSrc_Terminal_Id(), msisdns, msgContent.getBytes(), "");其中,构造函数的前两个参数设置为1,tp_Udhi值为0(表示没有协议头),msg_Fmt值为15(表示GBK编码)。其他使用jar包里例子的默认设置就行。
如果是长短信(msgContent.length() > 70),则采用如下构造方法:
// 采用UCS2编码格式int maxMessageLen = 140;byte[] contents = msgContent.getBytes("UnicodeBigUnmarked");int messageUCS2Len = contents.length;// 计算短信数量int count = messageUCS2Len / (maxMessageLen - 6);int rest = messageUCS2Len % (maxMessageLen - 6);if (rest > 0) {count++;}byte index = 1;for (int i = 0; i < count; i++) {byte[] smsHead = new byte[6]; // 6位协议头格式:05 00 03 XX MM NNsmsHead[0] = 0x05; // 表示剩余协议头的长度smsHead[1] = 0x00; // 这个值在GSM 03.40规范9.2.3.24.1中规定smsHead[2] = 0x03; // 这个值表示剩下短信标识的长度smsHead[3] = 0x00; // 这批短信的唯一标志(被拆分的多条短信,此值必需一致)。smsHead[4] = (byte) count; // 这批短信的数量smsHead[5] = index; // 当前短信是这批短信中第几条byte[] msgBytes = null;if (i != (count - 1)) {msgBytes = new byte[140];System.arraycopy(smsHead, 0, msgBytes, 0, 6);System.arraycopy(contents, i * (maxMessageLen - 6), msgBytes, 6, maxMessageLen - 6);} else {msgBytes = new byte[6 + rest];System.arraycopy(smsHead, 0, msgBytes, 0, 6);System.arraycopy(contents, i * (maxMessageLen - 6), msgBytes, 6, rest);}// 此处发送短信时,需要将TP_udhi字段设置为1,表示短信内容中含有协议头信息CMPPSubmitMessage msg = new CMPPSubmitMessage(1, 1, config.getRegistered_Delivery(), config.getMsg_level(), config.getService_Id(), config.getFee_UserType(), "", config.getTp_Pid(), 1, //表示有协议头0x08, //UCS2格式编码config.getMsg_Src(), config.getFee_Type(), config.getFee_Code(), null, null, config.getSrc_Terminal_Id(), msisdns, msgBytes,"");index++; }
2、SMPP短信构造方法:
/** * 构造消息体 * msisdns:要发送的手机号码 * msgContent:消息内容 */private FixedSMPPSubmitMessage[] productMsg(String msisdn, String msgContent);
华为Jar包的SMPP协议有bug,会导致长短信无法发送。因此需要对其jar包里的SMPPSubmitMessage.java类进行修正,即FixedSMPPSubmitMessage.java。该修正类的内容附在正文最后。
由于在开发时,短信中心不支持GBK编码,因此短短信和长短信都要通过UCS2编码进行发送。首先要判断要发送的内容是短短信还是长短信:
int maxMessageLen = 126;byte[] contents = msgContent.getBytes("ISO-10646-UCS-2");int messageUCS2Len = contents.length;如果是短短信(messageUCS2Len <= maxMessageLen),和CMPP类似,此处esmClass设置为0,表示没有协议头,dataCoding设置为0x08,表示UCS2编码。其他采用demo的默认值:
FixedSMPPSubmitMessage submitMsg = new FixedSMPPSubmitMessage("", (byte)0, config.getSourceAddrNpi(), config.getSourceAddr(), config.getDestAddrTon(), config.getDestAddrNpi(), "86" + msisdn, config.getEsmClass(), config.getProtocolId(), config.getPriorityFlag(), config.getScheduleDeliveryTime(), config.getValidityPeriod(), config.getRegisteredDelivery(), config.getReplaceIfPresentFlag(), config.getDataCoding(), config.getSmDefaultMsgId(), (byte)(contents.length), contents);
如果是长短信(messageUCS2Len > maxMessageLen),将esmClass的值设置为0x7f,表示有协议头,其他采用demo的默认值,构造方法如下:
int count = messageUCS2Len / (maxMessageLen - 6);int rest = messageUCS2Len % (maxMessageLen - 6);if (rest > 0) {count++;}for (int i = 0; i < count; i++) {byte[] head = new byte[6]; // 6位协议头格式:05 00 03 XX MM NNhead[0] = 0x05; // 表示剩余协议头的长度head[1] = 0x00; // 这个值在GSM 03.40规范9.2.3.24.1中规定head[2] = 0x03; // 这个值表示剩下短信标识的长度head[3] = 0x00; // 这批短信的唯一标志(被拆分的多条短信,此值必需一致)head[4] = (byte) count; // 这批短信的数量head[5] = (byte)(1 + i); // 当前短信是这批短信中第几条byte[] msgBytes = null;if (i != (count - 1)) {msgBytes = new byte[maxMessageLen];System.arraycopy(head, 0, msgBytes, 0, 6);System.arraycopy(contents, i * (maxMessageLen - 6), msgBytes, 6, maxMessageLen - 6);}else{msgBytes = new byte[6 + rest];System.arraycopy(head, 0, msgBytes, 0, 6);System.arraycopy(contents, i * (maxMessageLen - 6), msgBytes, 6, rest);}FixedSMPPSubmitMessage submitMsg = new FixedSMPPSubmitMessage("", (byte) 0, config.getSourceAddrNpi(), config.getSourceAddr(), config.getDestAddrTon(),config.getDestAddrNpi(), "86" + msisdn, (byte)0x7f, config.getProtocolId(),config.getPriorityFlag(), config.getScheduleDeliveryTime(), config.getValidityPeriod(), config.getRegisteredDelivery(),config.getReplaceIfPresentFlag(), config.getDataCoding(),config.getSmDefaultMsgId(), (byte) msgBytes.length,msgBytes);}
附件:FixedSMPPSubmitMessage.java
import com.huawei.insa2.comm.smpp.SMPPConstant;import com.huawei.insa2.comm.smpp.message.SMPPMessage;/** * This command is issued by the ESME to submit a short message to the SMSC for * transmission to a specified subscriber. When a real source address is * provided in a registered submit_sm request, the source address can be used as * the destination address for a delivery receipt. It can also be used in * identifying the message source in a CDR. This source address must fall in the * range of addresses associated with the bind command. Where the originator of * messages from the ESME is the ESME itself, or where the ESME does not have a * real source address, the source address fields may be defaulted to NULL, and * the source address will be taken from the SMSC administration “callback * address” for the particular ESME instance. The submit_sm operation can also * be used to replace a short message which has previously been submitted. This * is achieved by setting the replace_if_present_flag to 0x01 in the Interface. * The first message found in the SMSC whose source and destination match those * given in the submit_sm will have it’s text replaced by the text in the * short_message field of the submit_sm. * * */public class FixedSMPPSubmitMessage extends SMPPMessage {private StringBuffer strBuf;protected final String serviceType;protected final byte sourceAddrTon;protected final byte sourceAddrNpi;protected final String sourceAddr;protected final byte destAddrTon;protected final byte destAddrNpi;protected final String destinationAddr;protected final byte esmClass;protected final byte protocolId;protected final byte priorityFlag;protected final String scheduleDeliveryTime;protected final String validityPeriod;protected final byte registeredDelivery;protected final byte replaceIfPresentFlag;protected final byte dataCoding;protected final byte smDefaultMsgId;protected final byte smLength;protected final byte[] shortMessage;private String msisdn;public String getMsisdn() {return msisdn;}public void setMsisdn(String msisdn) {this.msisdn = msisdn;}/** * * @param serviceType * Var. Max 6. Indicates the type of service associated with the * message. Where not required this should be set to a single * NULL byte. * @param sourceAddrTon * Type of number for source. Where not required this should be * NULL. (See GSM 03.40 [2] 9.1.2.5) * @param sourceAddrNpi * Numbering Plan Indicator for source Where not required this * should be NULL. (See GSM 03.40 [2] 9.1.2.5) * @param sourceAddr * Address of SME which originated this message. This is the * source address of the short message submitted. This variable * length field may have leading spaces. Where not required this * should be a single NULL byte. * @param destAddrTon * Type of number for destination. Where not required this should * be NULL (See GSM 03.40 [2] 9.1.2.5) * @param destAddrNpi * Numbering Plan Indicator for destination Where not required * this should be NULL. (See GSM 03.40 [2] 9.1.2.5) * @param destinationAddr * Destination address of this short message. For mobile * terminated messages, this is the SME address of the target * subscriber. This variable length field may have leading * spaces. Where not required this should be a single NULL byte. * @param esmClass * Indication of message type. For the submit_sm command this * field is unused, and should be set to NULL. For the deliver_sm * command however, this field may identify the message as a * delivery receipt. * @param protocolId * GSM Protocol ID (See GSM 03.40 [2] 9.2.3.9) * @param priorityFlag * Designates the message as priority. Setting priority on a * message moves it to the top of the SMSC message queue for that * subscriber. 0 = non-priority (default) 1 = priority * >1=Reserved * @param scheduleDeliveryTime * The absolute date and time at which delivery of this message * must be attempted. The format is defined in section 7.5 Where * not required this should be a single NULL byte. * @param validityPeriod * The expiration time of this message. This is specified as an * absolute date and time of expiry. The format is defined in * section 7.5 Where not required this should be a single NULL * byte. * @param registeredDelivery * Flag indicating if the message is a registered short message * and thus if a Delivery Receipt is required upon the message * attaining a final state. 0=No receipt required (non-registered * delivery). 1=Receipt required (registered delivery) * >1=Reserved * @param replaceIfPresentFlag * Flag indicating if submitted message should replace an * existing message between the specified source and destination. * 0=Don’t Replace (default) 1=Replace >1=Reserved * @param dataCoding * GSM Data-Coding-Scheme ( See GSM 03.40 [2] 9.2.3.10) * @param smDefaultMsgId * Indicates the default short message to send, by providing an * index into the table of Predefined Messages set up by the SMSC * administrator. This should be set to NULL if a text message is * being sent. Range is 0x01 to 0x64. (See SMPP Applications * Guide [1] - Default Short Message). * @param smLength * Length of the text of the message in bytes. * @param shortMessage * Up to 160 bytes of data. This is the text that is transmitted * to the mobile station. Note that only ‘sm_length’ bytes will * be used. * @throws IllegalArgumentException */public FixedSMPPSubmitMessage(String serviceType, byte sourceAddrTon,byte sourceAddrNpi, String sourceAddr, byte destAddrTon,byte destAddrNpi, String destinationAddr, byte esmClass,byte protocolId, byte priorityFlag, String scheduleDeliveryTime,String validityPeriod, byte registeredDelivery,byte replaceIfPresentFlag, byte dataCoding, byte smDefaultMsgId,byte smLength, byte[] shortMessage) throws IllegalArgumentException {this.msisdn = destinationAddr;if (serviceType.length() > 5) {throw new IllegalArgumentException(SMPPConstant.SUBMIT_INPUT_ERROR+ ":serviceType " + SMPPConstant.STRING_LENGTH_GREAT + "5");}if (sourceAddr.length() > 20) {throw new IllegalArgumentException(SMPPConstant.SUBMIT_INPUT_ERROR+ ":sourceAddr " + SMPPConstant.STRING_LENGTH_GREAT + "20");}if (destinationAddr == null)throw new IllegalArgumentException(SMPPConstant.SUBMIT_INPUT_ERROR+ ":destinationAddr " + SMPPConstant.STRING_NULL);if (destinationAddr.length() > 20) {throw new IllegalArgumentException(SMPPConstant.SUBMIT_INPUT_ERROR+ ":destinationAddr " + SMPPConstant.STRING_LENGTH_GREAT+ "20");}if (scheduleDeliveryTime.length() != 0&& scheduleDeliveryTime.length() != 16) {throw new IllegalArgumentException(SMPPConstant.SUBMIT_INPUT_ERROR+ ":scheduleDeliveryTime "+ SMPPConstant.STRING_LENGTH_NOTEQUAL + "16");}if (validityPeriod.length() != 0 && validityPeriod.length() != 16) {throw new IllegalArgumentException(SMPPConstant.SUBMIT_INPUT_ERROR+ ":validityPeriod " + SMPPConstant.STRING_LENGTH_NOTEQUAL+ "16");}if (smLength > 254) {throw new IllegalArgumentException(SMPPConstant.SUBMIT_INPUT_ERROR+ ":smLength " + SMPPConstant.STRING_LENGTH_GREAT + "254");}if (shortMessage.length > 254) {throw new IllegalArgumentException(SMPPConstant.SUBMIT_INPUT_ERROR+ ":shortMessage " + SMPPConstant.STRING_LENGTH_GREAT+ "254");}this.serviceType = serviceType;this.sourceAddrTon = sourceAddrTon;this.sourceAddrNpi = sourceAddrNpi;this.sourceAddr = destinationAddr;this.destAddrTon = destAddrTon;this.destAddrNpi = destAddrNpi;this.destinationAddr = destinationAddr;this.esmClass = esmClass;this.protocolId = protocolId;this.priorityFlag = priorityFlag;this.scheduleDeliveryTime = scheduleDeliveryTime;this.validityPeriod = validityPeriod;this.registeredDelivery = registeredDelivery;this.replaceIfPresentFlag = replaceIfPresentFlag;this.dataCoding = dataCoding;this.smDefaultMsgId = smDefaultMsgId;this.smLength = smLength;this.shortMessage = shortMessage;int len = 33 + serviceType.length() + sourceAddr.length()+ destinationAddr.length() + scheduleDeliveryTime.length()+ validityPeriod.length() + smLength;super.buf = new byte[len];setMsgLength(len);setCommandId(4);setStatus(0);int pos = 16;System.arraycopy(serviceType.getBytes(), 0, super.buf, pos, serviceType.length());pos = pos + serviceType.length() + 1;super.buf[pos] = sourceAddrTon;pos++;super.buf[pos] = sourceAddrNpi;pos++;System.arraycopy(sourceAddr.getBytes(), 0, super.buf, pos, sourceAddr.length());pos = pos + sourceAddr.length() + 1;super.buf[pos] = destAddrTon;pos++;super.buf[pos] = destAddrNpi;pos++;System.arraycopy(destinationAddr.getBytes(), 0, super.buf, pos,destinationAddr.length());pos = pos + destinationAddr.length() + 1;super.buf[pos++] = esmClass;super.buf[pos++] = protocolId;super.buf[pos++] = priorityFlag;System.arraycopy(scheduleDeliveryTime.getBytes(), 0, super.buf, pos,scheduleDeliveryTime.length());pos = pos + scheduleDeliveryTime.length() + 1;System.arraycopy(validityPeriod.getBytes(), 0, super.buf, pos,validityPeriod.length());pos += (validityPeriod.length() + 1);super.buf[pos++] = registeredDelivery;super.buf[pos++] = replaceIfPresentFlag;super.buf[pos++] = dataCoding;super.buf[pos++] = smDefaultMsgId;super.buf[pos++] = smLength;System.arraycopy(shortMessage, 0, super.buf, pos, smLength);strBuf = new StringBuffer(600);strBuf.append(",serviceType=" + serviceType);strBuf.append(",sourceAddrTon=" + sourceAddrTon);strBuf.append(",sourceAddrNpi=" + sourceAddrNpi);strBuf.append(",sourceAddr=" + sourceAddr);strBuf.append(",destAddrTon=" + destAddrTon);strBuf.append(",destAddrNpi=" + destAddrNpi);strBuf.append(",destinationAddr=" + destinationAddr);strBuf.append(",esmClass=" + esmClass);strBuf.append(",protocolId=" + protocolId);strBuf.append(",priorityFlag=" + priorityFlag);strBuf.append(",scheduleDeliveryTime=" + scheduleDeliveryTime);strBuf.append(",validityPeriod=" + validityPeriod);strBuf.append(",registeredDelivery=" + registeredDelivery);strBuf.append(",replaceIfPresentFlag=" + replaceIfPresentFlag);strBuf.append(",dataCoding=" + dataCoding);strBuf.append(",smDefaultMsgId=" + smDefaultMsgId);strBuf.append(",smLength=" + smLength);strBuf.append(",shortMessage=" + shortMessage);}public FixedSMPPSubmitMessage(byte[] buf) throws IllegalArgumentException {super.buf = new byte[buf.length];System.arraycopy(buf, 0, super.buf, 0, buf.length);int pos = 16;for (; pos < this.buf.length; ++pos) {if (buf[pos] == 0) {break;}}int len = pos - 16;this.serviceType = new String(buf, 16, len);pos++;this.sourceAddrTon = buf[pos++];this.sourceAddrNpi = buf[pos++];int start = pos;for (; pos < this.buf.length; ++pos) {if (buf[pos] == 0) {break;}}this.sourceAddr = new String(buf, start, pos - start);pos++;this.destAddrTon = buf[pos++];this.destAddrNpi = buf[pos++];start = pos;for (; pos < this.buf.length; ++pos) {if (buf[pos] == 0) {break;}}this.destinationAddr = new String(buf, start, pos - start);pos++;this.esmClass = buf[pos++];this.protocolId = buf[pos++];this.priorityFlag = buf[pos++];this.scheduleDeliveryTime = new String(buf, pos, 16);pos += 17;this.validityPeriod = new String(buf, pos, 16);pos += 17;this.registeredDelivery = buf[pos++];this.replaceIfPresentFlag = buf[pos++];this.dataCoding = buf[pos++];this.smDefaultMsgId = buf[pos++];this.smLength = buf[pos++];this.shortMessage = buf;}public String getServiceType() {return serviceType;}public byte getSourceAddrTon() {return this.sourceAddrTon;}public byte getSourceAddrNpi() {return this.sourceAddrNpi;}public String getSourceAddress() {return sourceAddr;}public byte getDestAddrTon() {return this.destAddrTon;}public byte getDestAddrNpi() {return this.destAddrNpi;}public String getDestAddress() {return this.destinationAddr;}public byte getEsmClass() {return this.esmClass;}public byte getProtocolId() {return this.protocolId;}public String getScheduleDeliveryTime() {return this.scheduleDeliveryTime;}public String getValidityPeriod() {return this.validityPeriod;}public byte[] getShortMessage() {return this.shortMessage;}public String toString() {StringBuffer outBuf = new StringBuffer(600);outBuf.append("SMPPSubmitMessage: ");outBuf.append("PacketLength=" + getMsgLength());outBuf.append(",CommandID=" + getCommandId());outBuf.append(",Status=" + getStatus());outBuf.append(",SequenceID=" + getSequenceId());if (strBuf != null) {outBuf.append(strBuf.toString());}return outBuf.toString();}}
- 基于华为smproxy_20040730.jar的CMPP和SMPP的短信构造(支持长短信)
- CMPP协议对长短信的支持
- CMPP协议对长短信的支持
- 基于cmpp协议的超长短信格式
- 基于cmpp协议的超长短信格式
- 短信、长短信、彩信的PDU
- 短信、长短信、彩信的PDU
- CMPP和SMPP协议比较
- CMPP和SMPP协议比较
- CMPP和SMPP协议比较
- CMPP和SMPP协议比较
- CMPP和SMPP协议比较
- CMPP和SMPP协议比较
- CMPP和SMPP协议比较
- CMPP和SMPP协议比较
- CMPP和SMPP协议比较
- 长短信格式(cmpp)
- 基于CMPP短信开发遇到的丢包事件处理
- 如何进行个人知识管理?(一)
- shell编程用得到的正则表达式元字符
- [面经]百度商务搜索部实习生面经(已经被拒,倒在三面上了)
- 关于IRET指令
- x86架构与ARM架构处理器
- 基于华为smproxy_20040730.jar的CMPP和SMPP的短信构造(支持长短信)
- 文思工资查询地址
- mybatis 使用总结
- 表格里单词不换行问题解决
- mysql中主键包含多字段问题
- 关于register_globals的问题
- Java如何打包成.exe
- activity使用theme.dialog且activity中有dialog时按返回按钮dialog消失activity不关闭的解决方法
- 第四节中断处理