移动短信网关SP端

本文档展示了如何实现SP服务器,通过CMPP协议连接ISMG,并启动发送和接收线程。代码中包括SPServer类用于发送Submit消息和获取已发送的Deliver消息,以及CMPPConntor类作为接收和处理消息的线程,处理Deliver消息的响应,包括发送DeliverResp消息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 SP端

//发起向ISMG连接并启动收发线程

public class SPServer {
  private CMPPConntor conn;//CMPP连结对象
 //保存接收到所有sp发来的submit消息队列
 private List<MsgSubmit> submitsResult=new ArrayList();
 //保存所有己发送的Deliver消息
 private List<MsgDeliver> deliversResult=new ArrayList();
 
  private String spPWD;
  private String spId;
 
  public SPServer(String spId,String spPWD){
   this.spId=spId;
   this.spPWD=spPWD;
  }
 
  /**
   * 向ISMG端发送一条消息
   * @param mobile:手机号
   * @param spCode:sp号
   * @param msg:消息内容
   * @return:是否发送成功
   */
  public boolean sendSubmit(String mobile,String spCode,String msg){
   byte[] mb=msg.getBytes();
   int msgLen=mb.length;
  
   int totalLen=12+8+1+1+1+1+10+1+32+1+1+1+1+6+2+6+17+17+21
   +1+32+1+1+msgLen+20;
  
   MsgSubmit ms=new MsgSubmit();
   ms.setTotal_Length(totalLen);
   ms.setCommand_Id(MsgCommand.CMPP_SUBMIT);
   ms.setSequence_Id(Utils.getSeq());
   ms.setDest_terminal_Id(spCode);
   ms.setSrc_Id(this.spId);
   ms.setMsg_src(spCode);
   ms.setMsg_Length((byte)msgLen);
   ms.setMsg_Content(msg);
   ms.setRegistered_Delivery((byte)0);
  
   byte[] data=cn.netjava.cmpp.util.MsgTools.packMsg(ms);
   //发送
  return conn.sendMsg(data);

  }
 
  /**
   * 返回己发送成功,即收到应答的Deliver消息
   * @return
   */
  public List<MsgDeliver> getRecvDeliver(){
   java.util.List<MsgDeliver> dl=new ArrayList();
  synchronized(this.deliversResult){
   dl.addAll(deliversResult);
   deliversResult.clear();
  }
  return dl;
  }
 
 
  /**
   * 返回己发送成功的Submit消息
   * @return
   */
  public List<MsgSubmit> getSendedMsgSubmit(){
   java.util.List<MsgSubmit> dl=new ArrayList();
  synchronized(this.submitsResult){
   dl.addAll(submitsResult);
   submitsResult.clear();
  }
  return dl;
  }
 
 
 /**
  * 在指定端口上启动服务器
  * @param port
  */
 public void startSP(String ip,int port){
  try{
    
//   //绑到到服务器上指定的IP地址
    java.net.Socket sc=new java.net.Socket(ip,port);
 SysteLog.INFO("连结服务器OK:", sc.getLocalSocketAddress().toString());
   //包装为cmpp连结对象
     conn=new CMPPConntor(sc,submitsResult,deliversResult);
     int code=conn.login(spId, spPWD);
   if(0==code){
    conn.start();
    SysteLog.INFO("sp端","客户机登陆成功,接收线程己启动");
   }else{
    conn.close();
    SysteLog.INFO("sp端","客户机登陆失败!errorCode "+code);
   }
   
  
  }catch(Exception ef){
   ef.printStackTrace();
  }
  
 
 }
 
 

}

 

//接收,处理消息类

public class CMPPConntor extends Thread {
 
 private java.net.Socket sc;//网络连结对象
 private int sendCount;//一秒内己发送的计数器
 //从连结上得到的输入输出流
 private java.io.DataInputStream dins;
 private java.io.DataOutputStream dous;
    //存放己回过应答的Submit消息
 private List<MsgSubmit> submitsResult;
 private List<MsgDeliver> deliversResult;
 
  //接收到,等处理回复的Deliver队列
    private List<MsgDeliver> delivers=new ArrayList();
   
 
    //己发送,等待应答的Submit队列
    private Map<Integer,MsgSubmit> submitList1=new HashMap();
   
 
    private boolean isRunning=true;//运行标志
 
 /**
  * 创建一个cmpp连结对象
  * @param sc:tcp/ip连结
  * @param submits:保存接收到的Submit消息对象
  * @throws Exception
  */
   public CMPPConntor(java.net.Socket sc,List<MsgSubmit> submitsResult,List<MsgDeliver> deliversResult)throws Exception{
    try{
    this.submitsResult=submitsResult;
    this.deliversResult=deliversResult;
    this.sc=sc;
    sc.setReceiveBufferSize(2048);//设定Socket缓冲区大小
//    sc.setSoTimeout(1000);//超时为1秒  //如果超时到了,会返回什么呢??
    dins=new java.io.DataInputStream(sc.getInputStream());
    dous=new java.io.DataOutputStream(sc.getOutputStream());
    }catch(Exception ef){
     ef.printStackTrace();
    }
   }
  
   /**
    * 本连结对象上一秒己发送消息的个数
    * @return
    */
   public int getSendCount(){
  return sendCount;
 }
  
  
  
  
   
  /**
   * 在本连结上发送己打包后的消息的字节
   * @param data:要发送消息的字节
   */
   public boolean sendMsg(byte[] data) {
    try{
     Utils.debugData("SP端发出的原始数据>>>:", data);
  sendCount++;
    //可以将多条消息打到一个包中
    dous.write(data);
    dous.flush();
    return true;
    }catch(Exception ef){
     ef.printStackTrace();
    }
    return false;
   }
  
 
   /**
    * 本连结由SP端调用,以向ISMG发送登陆请求
    * @param spid :sp企业ID
    * @param pwd: SP密码
    * @return :登陆请求的应答结果
    * @throws Exception
    */
   public int login(String spid,String pwd)throws Exception{
    //构造登陆消息对象
    MsgLogin ml=new MsgLogin();
    ml.setTotal_Length(12+6+16+1+4);
    ml.setCommand_Id(MsgCommand.CMPP_CONNECT);
    ml.setSequence_Id(Utils.getSeq());
   
    ml.setSource_Addr(spid);
    byte[] md5=Utils.getLoginMd5(spid, pwd);
    ml.setAuthenticatorSource(md5);
    ml.setVersion((byte)14);
    ml.setTimestamp(Integer.parseInt(Utils.getMMDDHHMMSS()));
    //发送登陆消息包
    byte[] ld=MsgTools.packMsg(ml);
     this.sendMsg(ld);
    //读取应答:
    byte[] data=recv();
     MsgHead msg=MsgTools.parseMsg(data);
    //解包为一个MsgLoginResp对象
    MsgLoginResp mlr=(MsgLoginResp)msg;
    return mlr.getStatus();
   
   }
  
 
    //关闭连结
   public void close(){
    try{
    isRunning=false;
    this.sc.close();
    }catch(Exception ef){
   //  ef.printStackTrace();
    }
   }
  
  
   /**
    * IMSG循环接收消息的线程
    */
   public void run(){
    processDeliver();//启动处理接收Deliver线程
    while(true){
     byte[] b=recv();//接收消息,以数据据块的方式读取
     //在这里,还有可能收到login请求
          if(null==b){
           break;
          }
         
    //将读到的数据块解包为对应的消息对象
       MsgHead msg=   MsgTools.parseMsg(b);
       SysteLog.INFO("客户机收到的消息", msg);
     //收到的是SP发来的Submit消息
       if(msg.getCommand_Id()==MsgCommand.CMPP_DELIVER){
        System.out.println("1");
        MsgDeliver ms=(MsgDeliver)msg;
        if(delivers.size()>16){
      //回一个应答state为8的消息  
        }else{
       //将收到的消息加入到处理队列中
         delivers.add(ms);
        }
       }
     //收到的是SP发来的DELIVER应答消息
       if(msg.getCommand_Id()==MsgCommand.CMPP_SUBMIT_RESP){
        System.out.println("2");
      MsgSubmitResp ms=(MsgSubmitResp)msg;
      int mid=ms.getSequence_Id();
      MsgSubmit md=submitList1.get(mid);
      if(md!=null){//如果收到了应答
       //应答结果保存到Deliver消息中
       int state=ms.getResult();
       md.setSendResult(state);
       //加入到处理队列中
       submitsResult.add(md);
       //从等待应答队列中移除
       submitList1.remove(mid);
        }
         }
       //如果收到其它消息

    }
   }
 
   /**
    * 处理接收到的Deliver消息的应答回复
    *  流量未超标
    * 1.负责生成msgid,
    * 2.回应答,
    * 3.将本条MsgDeliver消息交给其它模块处理
    */
   private void processDeliver(){
    java.lang.Runnable runner=new java.lang.Runnable(){
     public void run(){
      while(true){
       //处理队列1
     for(int i=0;i<delivers.size();i++){
       MsgDeliver ms=delivers.get(i);
      //取出来,创建一个应答消息对象回应答
      sendDeliverResp(ms);
      //将发送过应答结果的消息放到回收队列中
      deliversResult.add(ms);
      delivers.remove(i);
       }
      sleepThread(10);
     }
     }
    };
    Thread t=new Thread(runner);
    t.start();
   }
  
  
   //发送一个Deliver消息对应的应答消息
   private void sendDeliverResp(MsgDeliver ms){
    
    MsgDeliverResp rs=new MsgDeliverResp();
    rs.setTotal_Length(12+8+4);
    rs.setCommand_Id(MsgCommand.CMPP_DELIVER_RESP);
    rs.setSequence_Id(ms.getSequence_Id());
    //模拟生成消息ID
    long mid=java.util.UUID.randomUUID().getLeastSignificantBits();
    ms.setMsg_Id(mid);
    rs.setMsg_Id(mid);
    rs.setResult(0);    //消息正确
   
    byte[] data=MsgTools.packMsg(rs);
    this.sendMsg(data);
   
   }
  
  
  
   private void sleepThread(int i){
    try{
     Thread.sleep(i);
    }catch(Exception ef){
    
    }
   }
 
  
   /**
    * 从输入流上读取消息的原始数据块,注:不含消息头总长四个字节
    */
   private byte[] recv(){
    try{
    int len=dins.readInt();
    //cmpp消息最长是不会招过200字节的
    //1.恶意消息 10 10000
    if((len>0)&&(len<500)){
    byte[] data=new byte[len-4];
   
    dins.readFully(data);  //如果超时了呢?
  //这里的data,才是最原始的数据
    Utils.debugData("SP端收到的原始数据<<<:", data);
    return data;
    }else{
     //1.丢出异常
     //2.要么断开它
    }
    }catch(Exception ef){
     ef.printStackTrace();
    }
    return null;
   }
  
 
 
 
 
 
 
}

 


demo下载地址:http://download.youkuaiyun.com/detail/layhaokeai/3705396

 

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值