package cn.richinfo.cmail.vasp.common.util; import ie.omk.smpp.Address; import ie.omk.smpp.Connection; import ie.omk.smpp.message.BindResp; import ie.omk.smpp.message.EnquireLink; import ie.omk.smpp.message.EnquireLinkResp; import ie.omk.smpp.message.SMPPPacket; import ie.omk.smpp.message.SMPPResponse; import ie.omk.smpp.message.SubmitSM; import ie.omk.smpp.message.SubmitSMResp; import ie.omk.smpp.util.EncodingFactory; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import cn.richinfo.cmail.common.config.PropertiesUtil; /** * @todo 长连接发短信 * @date 2017年8月15日 * @author linying */ public class SMPPUtil { private Logger logger = Logger.getLogger(SMPPUtil.class); private boolean connected = false; // 是否已连接 private boolean received = false; // 是否接收心跳包 private Connection conn = null;// ESME到SMSC的连接 private SMPPUtil() { } public static final SMPPUtil getInstance() { return SMPPUtilHolder.SMPP_UTIL; } /** * @todo 打开链接 * @throws Exception */ private void openLink() throws Exception { logger.info("open smsc service..."); String host = PropertiesUtil.getProperty("zte.notice.smsc.host"); int port = PropertiesUtil.getPropertyInt("zte.notice.smsc.port", 0); String systemId = PropertiesUtil.getProperty("zte.notice.smsc.systemId"); String password = PropertiesUtil.getProperty("zte.notice.smsc.password"); String systemType = PropertiesUtil.getProperty("zte.notice.smsc.systemType"); logger.info(String.format("openLink parameter | host=%s | port=%s | systemId=%s | password=%s | systemType=%s", host, port, systemId, password, systemType)); if (StringUtils.isEmpty(host) || StringUtils.isEmpty(systemId) || StringUtils.isEmpty(password) || StringUtils.isEmpty(systemType) || port == 0) { logger.error("parameter is empty"); return; } conn = new Connection(host, port); conn.autoAckLink(true); conn.autoAckMessages(true); BindResp resp = conn.bind(Connection.TRANSMITTER, systemId, password, systemType); if (null != resp && resp.getCommandStatus() == 0) { connected = true; // new Thread(new KeepHeartbeat()).start(); // 发送心跳 new Thread(new ReceivePackets()).start(); // 接收心跳 } } /** * * @todo 发送心跳 * @date 2017年8月15日 * @author linying */ class KeepHeartbeat implements Runnable { private long delay = PropertiesUtil.getPropertyLong("zte.notice.smsc.keep.delay"); public void run() { while (connected) { try { Thread.sleep(delay);// 心跳延时 EnquireLinkResp resp = conn.enquireLink(); if (null != resp && resp.getCommandStatus() == 0) { logger.info("[system request packet ok]"); } else { logger.info("[system request packet err]"); } } catch (Exception e) { logger.error(e); closeLink(); } } } } /** * * @todo 接收心跳 * @date 2017年8月15日 * @author linying */ class ReceivePackets implements Runnable { public void run() { while (connected) { try { if (received) { SMPPPacket packet = conn.readNextPacket(); if (null != packet && packet.getCommandStatus() == 0) { logger.info("[smsc request packet ok]"); EnquireLink link = new EnquireLink(); link.setSequenceNum(packet.getSequenceNum()); conn.ackEnquireLink(link); } else { logger.info("[smsc request packet err]"); } } logger.info("[smsc request packet stop]"); Thread.sleep(10000); } catch (Exception e) { logger.error(e); closeLink(); } } } } /** * @todo 关闭链接 * @return void */ private void closeLink() { logger.info("close smsc service..."); connected = false; received = false; try { if (conn != null && conn.isBound()) { conn.unbind(); } conn = null; } catch (Exception e) { logger.error(e); } } /** * @todo 发送短信 * @param address * @param text * @return String * @throws Exception */ public String sendSms(String address, String text) throws Exception { int ton = PropertiesUtil.getPropertyInt("zte.notice.sms.ton", 0); int npi = PropertiesUtil.getPropertyInt("zte.notice.sms.npi", 0); String source = PropertiesUtil.getProperty("zte.notice.sms.sourceAddress"); int encode = PropertiesUtil.getPropertyInt("zte.notice.sms.encoding", 8); int count = 1; return sendSms(ton, npi, source, address, text, encode, count); } private String sendSms(int ton, int npi, String source, String address, String text, int encode, int count) throws Exception { // 发送短信中,停止接收心跳 received = false; // 没有绑定 if (!connected) { openLink(); } logger.info("connected is true"); SubmitSM sm = (SubmitSM) conn.newInstance(SMPPPacket.SUBMIT_SM); if (StringUtils.isNotEmpty(source)) { sm.setSource(new Address(ton, npi, source)); } sm.setDestination(new Address(0, 0, address)); sm.setMessageText(text); sm.setMessageEncoding(EncodingFactory.getInstance().getEncoding(encode)); SMPPResponse response = (SubmitSMResp) conn.sendRequest(sm); received = true; // 发送失败,递归重试3次 if (response == null || response.getCommandStatus() != 0) { Thread.sleep(300); logger.error("send failed is retrying " + count); count++; if (count > 3) { return "send failed"; } sendSms(ton, npi, source, address, text, encode, count); } logger.info("send success"); return "send success"; } /** * @todo SMPPUtil单例 * @date 2017年8月15日 * @author linying */ private static class SMPPUtilHolder { private static final SMPPUtil SMPP_UTIL = new SMPPUtil(); } }
#heart beat delay(milliseconds) zte.notice.smsc.keep.delay=20000 #heart beat message zte.notice.smsc.keep.message=message[send heart beat data package] #stop the number of heart beats zte.notice.smsc.keep.count=5 #the request conten to send to the SMSC zte.notice.msg=【%s】你有1封新邮件,来自%s,主题是%s #the hostname of the SMSC. zte.notice.smsc.host=127.0.0.1 #the port to connect to. If 0, use the default SMPP port * number. zte.notice.smsc.port=80 #the system ID to identify as to the SMSC. zte.notice.smsc.systemId=0 #password to use to authenticate to the SMSC. zte.notice.smsc.password=0 #the system type to bind as. zte.notice.smsc.systemType=0 #SMS coding(1.US-ASCII, 3.ISO-8859-1, 8.ISO-10646-UCS-2) zte.notice.sms.encoding=8 #the type of number zte.notice.sms.ton=0 #the numbering plan indicator zte.notice.sms.npi=0 #source address zte.notice.sms.sourceAddress=88888888 #new mail notification URL zte.notice.url=http://127.0.0.1/vaservices/TestURL?act=1&msisdn=%s