一.联通SGIP网络架构图
SMG是具有短消息转发功能的短消息网关。全国可以有多个SMG网关,SMG网关之间通过互联网等方式实现网络互联。每一个SMG同时与多个SMSC以及多个SP连接。全网具有唯一有效的GNS,GNS负责全局路由表的维护与更新;为了确保路由表存储的安全性,网络中设置主备用GNS,两个GNS要保持一致性。每一个SMG都和GNS连接。SMG与SP、SMG与GNS以及SMG与SMG之间的通信协议为SGIP协议。SMG与SMSC之间的通信统一采用SMPP3.3协议。
其中,短信接入商以SP的角色接入:
二.开发工具包
https://gitee.com/cww-knight/SMSGate
三.和联通侧的约定
1.SMG 的host,port,LoginName,LoginPassword.
2.SP 的IP,PORT NodeId(节点编码)
3.企业编码(corp_id),接入号(sp_number)
四.代码开发
SpClient 初始化
final EndpointManager manager = EndpointManager.INS; SgipClientEndpointEntity client = new SgipClientEndpointEntity(); client.setId("sgip-client"); client.setNodeId(1l);//sp node_id client.setHost("smg_server"); client.setPort(8882);//smg_server port client.setLoginName("smg_loginname"); client.setLoginPassowrd("smg_loginpassword"); client.setChannelType(EndpointEntity.ChannelType.DUPLEX); client.setIdleTimeSec((short)300); client.setMaxChannels((short)1); client.setRetryWaitTimeSec((short)100); client.setUseSSL(false); client.setReSendFailMsg(true); List<BusinessHandlerInterface> clienthandlers = new ArrayList<BusinessHandlerInterface>(); client.setBusinessHandlerSet(clienthandlers); try{ manager.addEndpointEntity(client); manager.openEndpoint(client); }catch (Exception e){ } manager.startConnectionCheckTask();
SpClient 发消息
SgipSubmitRequestMessage msg = new SgipSubmitRequestMessage(); msg.setSequenceNo(sendMsgDto.getMsgId()); msg.setSpnumber("#接入号#"); msg.setUsernumber("#目标手机号(86开头)#"); msg.setCorpid("#企业编号#"); msg.setServicetype("1"); short feeType=0; msg.setFeetype(feeType); msg.setFeevalue("0"); msg.setGivenvalue("0"); msg.setAgentflag(feeType); msg.setMsgContent("短信内容"); ChannelUtil.syncWriteLongMsgToEntity("sgip-client", msg);
SpServer 初始化
final EndpointManager manager = EndpointManager.INS; SgipServerEndpointEntity server = new SgipServerEndpointEntity(); server.setId("spserver"); server.setHost("0.0.0.0"); server.setPort(9999);//Sp Server port server.setValid(true); server.setUseSSL(false); SgipServerChildEndpointEntity child = new SgipServerChildEndpointEntity(); child.setId("spnode"); child.setNodeId(1l);//节点编码 child.setLoginName(""); child.setLoginPassowrd(""); child.setValid(true); child.setChannelType(EndpointEntity.ChannelType.DUPLEX); child.setMaxChannels((short)10); child.setRetryWaitTimeSec((short)30); child.setMaxRetryCnt((short)3); child.setReSendFailMsg(false); child.setIdleTimeSec((short)300); child.setSupportLongmsg(EndpointEntity.SupportLongMessage.SEND); //接收长短信时不自动合并 List<BusinessHandlerInterface> serverhandlers = new ArrayList<BusinessHandlerInterface>(); serverhandlers.add(spSgipReportRequestMessageHandler); serverhandlers.add(spSgipMessageReceiveHandler); child.setBusinessHandlerSet(serverhandlers); server.addchild(child); try{ manager.addEndpointEntity(server); manager.openEndpoint(server); }catch (Exception e){ }
SpServer 处理Report(短信发送状态)和Deliver(上行短信)消息
以Report消息为例:spSgipReportRequestMessageHandler
package com.sms.demo.service.handler; import com.alibaba.fastjson.JSON; import com.sms.demo.datamodel.ReportMsgDto; import com.zx.sms.codec.sgip12.msg.SgipReportRequestMessage; import com.zx.sms.codec.sgip12.msg.SgipReportResponseMessage; import com.zx.sms.handler.sgip.SgipReportRequestMessageHandler; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.Date; @ChannelHandler.Sharable @Slf4j @Component public class SpSgipReportRequestMessageHandler extends SgipReportRequestMessageHandler { @Resource private KafkaTemplate<String,String> kafkaTemplate; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if(msg instanceof SgipReportRequestMessage){ // System.out.println("收到report:"+msg); log.info("收到report消息:{}",msg); SgipReportRequestMessage reportMsg= (SgipReportRequestMessage) msg; if(reportMsg.getReporttype()==0){ //TODO 处理submit消息的状态报告 } SgipReportResponseMessage resp = new SgipReportResponseMessage((reportMsg).getHeader()); resp.setResult((short)0); resp.setTimestamp(((SgipReportRequestMessage)msg).getTimestamp()); ctx.channel().writeAndFlush(resp); }else{ ctx.fireChannelRead(msg); } } @Override public String name() { return "SgipReportRequestMessageHandler"; } }