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