diff --git a/beacon-smsgateway/pom.xml b/beacon-smsgateway/pom.xml index e70e8b1..ed8fccf 100644 --- a/beacon-smsgateway/pom.xml +++ b/beacon-smsgateway/pom.xml @@ -53,6 +53,16 @@ beacon-common 1.0-SNAPSHOT + + + io.netty + netty-all + + + + org.apache.commons + commons-lang3 + \ No newline at end of file diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smmgateway/SmsGatewayApplication.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/SmsGatewayApplication.java similarity index 94% rename from beacon-smsgateway/src/main/java/com/mashibing/smmgateway/SmsGatewayApplication.java rename to beacon-smsgateway/src/main/java/com/mashibing/smsgateway/SmsGatewayApplication.java index d573d22..c42b689 100644 --- a/beacon-smsgateway/src/main/java/com/mashibing/smmgateway/SmsGatewayApplication.java +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/SmsGatewayApplication.java @@ -1,4 +1,4 @@ -package com.mashibing.smmgateway; +package com.mashibing.smsgateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/config/RabbitMQConfig.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/config/RabbitMQConfig.java new file mode 100644 index 0000000..fa30546 --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/config/RabbitMQConfig.java @@ -0,0 +1,29 @@ +package com.mashibing.smsgateway.config; + +import org.springframework.amqp.core.AcknowledgeMode; +import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer; + +/** + * @author heqijun + * @ClassName: RabbitMQConfig + * @Description: 配置针对指定消费者的配置可以用配置类的方式 + * @date 2025/6/13 16:04 + */ + +//@Configuration +public class RabbitMQConfig { + + // @Bean + public SimpleRabbitListenerContainerFactory gatewayContainerFactory(ConnectionFactory connectionFactory, + SimpleRabbitListenerContainerFactoryConfigurer configurer) { + SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory = new SimpleRabbitListenerContainerFactory(); + simpleRabbitListenerContainerFactory.setConcurrentConsumers(5); + simpleRabbitListenerContainerFactory.setPrefetchCount(10); + simpleRabbitListenerContainerFactory.setAcknowledgeMode(AcknowledgeMode.MANUAL); + configurer.configure(simpleRabbitListenerContainerFactory, connectionFactory); + return simpleRabbitListenerContainerFactory; + } + +} \ No newline at end of file diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/mq/SmsGatewayListener.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/mq/SmsGatewayListener.java new file mode 100644 index 0000000..03b44fd --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/mq/SmsGatewayListener.java @@ -0,0 +1,32 @@ +package com.mashibing.smsgateway.mq; + +import com.mashibing.common.pojo.StandardSubmit; +import com.rabbitmq.client.Channel; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +/** + * @author heqijun + * @ClassName: SmsGatewayListener + * @Description: TODO(这里用一句话描述这个类的作用) + * @date 2025/6/13 14:51 + */ + +@Slf4j +@Component +public class SmsGatewayListener { + + @RabbitListener(queues = {"${gateway.sendtopic}"}) + public void consume(StandardSubmit submit, Channel channel, Message message) throws IOException { + log.info("【网关模块】接收到消息,submit={}", submit); + + // 完成与运营商交互,发送一次请求,接收两次响应 + + channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); + + } +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/CMPPDecoder.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/CMPPDecoder.java new file mode 100644 index 0000000..e9778ae --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/CMPPDecoder.java @@ -0,0 +1,70 @@ +package com.mashibing.smsgateway.netty4; + +import com.mashibing.smsgateway.netty4.entity.CmppActiveTestResp; +import com.mashibing.smsgateway.netty4.entity.CmppDeliver; +import com.mashibing.smsgateway.netty4.entity.CmppSubmitResp; +import com.mashibing.smsgateway.netty4.utils.Command; +import com.mashibing.smsgateway.netty4.utils.MsgUtils; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import org.apache.commons.lang3.ArrayUtils; + +import java.util.List; + +/** + * 中国移动给咱们响应信息时,通过当前Decoder接收并做数据的解析 + */ +public class CMPPDecoder extends ByteToMessageDecoder { + + + + @Override + protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list){ + //字节数组 + byte[] buf = new byte[byteBuf.readableBytes()]; + //读取数据到字节数组 + byteBuf.readBytes(buf); + + //开始解析数据,先提取出长度字段标识长度的数据,也就是该条消息 + //4位 消息长度 + int totalLength = MsgUtils.bytesToInt(ArrayUtils.subarray(buf, 0, 4)); + //获取到该长度的字节数组 + byte[] bytes = ArrayUtils.subarray(buf, 0, totalLength); + + //获取到响应类型,也就是哪个接口的响应,4位 + int commandId = MsgUtils.bytesToInt(ArrayUtils.subarray(bytes, 4, 8)); + + //连接请求响应 + switch (commandId) { + case Command.CMPP_ACTIVE_TEST: + System.out.println("-----------------接收到链路检测-----------------"); + channelHandlerContext.writeAndFlush(new CmppActiveTestResp()); + break; + case Command.CMPP_ACTIVE_TEST_RESP: + System.out.println("--------------接收到链路应答--------------"); + break; + case Command.CMPP_DELIVER: + System.out.println("-------------状态报告---------------"); + CmppDeliver deliver=new CmppDeliver(bytes); + list.add(deliver); + break; + case Command.CMPP_SUBMIT_RESP: + System.out.println("-------------接收到短信提交应答-------------"); + CmppSubmitResp submitResp=new CmppSubmitResp(bytes); + list.add(submitResp); + break; + case Command.CMPP_QUERY_RESP: + System.out.println("-------------接收到短信查询应答-------------"); + break; + case Command.CMPP_CONNECT_RESP: + System.out.println("-------------请求连接应答-------------"); + //服务器端告诉客户端已接受你的连接 + break; + default: + System.out.println("暂无解析"+commandId); + break; + } + //list.add(commandId); + } +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/CMPPEncoder.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/CMPPEncoder.java new file mode 100644 index 0000000..6f2a745 --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/CMPPEncoder.java @@ -0,0 +1,36 @@ +package com.mashibing.smsgateway.netty4; + +import com.mashibing.smsgateway.netty4.entity.CmppMessageHeader; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; + +/** + * 编码 + */ +public class CMPPEncoder extends MessageToByteEncoder { + + public CMPPEncoder(){ + super(false); + } + + @Override + protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { + if (msg instanceof byte[]){ + out.writeBytes((byte[])msg); + }else if(msg instanceof Integer){ + out.writeInt((Integer)msg); + }else if(msg instanceof Byte){ + out.writeByte((Byte)msg); + }else if(msg instanceof Long){ + out.writeLong((Long)msg); + }else if(msg instanceof String){ + out.writeBytes(((String)msg).getBytes("UTF-16BE")); + }else if (msg instanceof Character){ + out.writeChar((Character)msg); + }else if (msg instanceof CmppMessageHeader){ + CmppMessageHeader c=(CmppMessageHeader)msg; + out.writeBytes(c.toByteArray()); + } + } +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/CMPPHandler.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/CMPPHandler.java new file mode 100644 index 0000000..00d2e89 --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/CMPPHandler.java @@ -0,0 +1,48 @@ +package com.mashibing.smsgateway.netty4; + + +import com.mashibing.smsgateway.netty4.entity.CmppDeliver; +import com.mashibing.smsgateway.netty4.entity.CmppSubmitResp; +import com.mashibing.smsgateway.netty4.utils.MsgUtils; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * 主要业务 handler,运营商响应信息 + */ +public class CMPPHandler extends SimpleChannelInboundHandler { + private final static Logger log = LoggerFactory.getLogger(CMPPHandler.class); + + @Override + protected void channelRead0(ChannelHandlerContext context, Object msg) throws Exception { + + if (msg instanceof CmppSubmitResp){ + CmppSubmitResp resp=(CmppSubmitResp)msg; + log.info("-------------接收到短信提交应答-------------"); + log.info("----自增id:"+resp.getSequenceId()); + log.info("----状态:"+ resp.getResult()); + log.info("----第一次响应:"+resp.getMsgId()); + } + + if (msg instanceof CmppDeliver){ + CmppDeliver resp=(CmppDeliver)msg; + // 是否为状态报告 0:非状态报告1:状态报告 + if (resp.getRegistered_Delivery() == 1) { + // 如果是状态报告的话 + log.info("-------------状态报告---------------"); + log.info("----第二次响应:"+resp.getMsg_Id_DELIVRD()); + log.info("----手机号:"+resp.getDest_terminal_Id()); + log.info("----状态:"+resp.getStat()); + } else { + //用户回复会打印在这里 + log.info(""+ MsgUtils.bytesToLong(resp.getMsg_Id())); + log.info(resp.getSrc_terminal_Id()); + log.info(resp.getMsg_Content()); + } + } + } + +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/HeartHandler.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/HeartHandler.java new file mode 100644 index 0000000..831cf1b --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/HeartHandler.java @@ -0,0 +1,45 @@ +package com.mashibing.smsgateway.netty4; + + +import com.mashibing.smsgateway.netty4.entity.CmppActiveTest; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.timeout.IdleState; +import io.netty.handler.timeout.IdleStateEvent; + + +/** + * 心跳Handler + */ +public class HeartHandler extends ChannelInboundHandlerAdapter { + + private NettyClient client; + public HeartHandler(NettyClient client){ + this.client=client; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + System.out.println("初始化创建连接。。。"); + super.channelActive(ctx); + } + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + IdleStateEvent event = (IdleStateEvent) evt; + IdleState state = event.state(); + if (state == IdleState.WRITER_IDLE || state == IdleState.ALL_IDLE) { + client.submit(new CmppActiveTest()); + System.out.println("心跳启动!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + } + } else { + super.userEventTriggered(ctx, evt); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + super.channelInactive(ctx); + client.reConnect(10); + } +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/NettyClient.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/NettyClient.java new file mode 100644 index 0000000..bd49084 --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/NettyClient.java @@ -0,0 +1,136 @@ +package com.mashibing.smsgateway.netty4; + +import com.mashibing.smsgateway.netty4.entity.CmppConnect; +import com.mashibing.smsgateway.netty4.entity.CmppMessageHeader; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; + + +/** + * 封装的netty客户端 + */ +public class NettyClient { + + // 通道 + private Channel channel; + // IP + private String host; + // 端口 + private int port; + // 用户名 + private String serviceId; + // 密码 + private String pwd; + + // 构建NettyClient + public NettyClient(String host, int port, String serviceId, String pwd) { + this.host = host; + this.port = port; + this.serviceId = serviceId; + this.pwd = pwd; + } + + // 开启连接 + public void start() { + try { + doConnect(host, port); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + // 在保持连接的状态下提交信息 + public boolean submit(CmppMessageHeader submit) { + if (isActive()) { + channel.writeAndFlush(submit); + return true; + } + return false; + } + + // 是否保持连接 + public boolean isActive() { + if (channel == null) { + return false; + } + if (!channel.isOpen() || !channel.isActive() || !channel.isWritable()) { + //channel没开 或 没激活 + return false; + } + return true; + } + + + /** + * 重连机制 在 channelInactive 触发时调用 + * + * @param reConnect + */ + public void reConnect(int reConnect) { + int times = 0; + while (true && times < reConnect) { + try { + if (!isActive()) { + start(); + } else { + try { + Thread.sleep(10 * 1000); + times++; + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } catch (Exception ex) { + System.out.println("尝试重连...:" + host + ":" + port + " / " + serviceId); + try { + Thread.sleep(10 * 1000); + times++; + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + /** + * 建立连接 + * @param host + * @param port + * @throws InterruptedException + */ + public void doConnect(final String host, final int port) throws InterruptedException { + + //创建线程组 - 手动设置线程数,默认为cpu核心数2倍 + EventLoopGroup eventLoopGroup = new NioEventLoopGroup(4); + //创建引导程序 + Bootstrap bootstrap = new Bootstrap(); + //保持长连接 + bootstrap.option(ChannelOption.SO_KEEPALIVE, true); + //将线程加入bootstrap + bootstrap.group(eventLoopGroup) + .remoteAddress(host, port) + //使用指定通道类 + .channel(NioSocketChannel.class) + //设置日志 + .handler(new LoggingHandler(LogLevel.INFO)) + //重写通道初始化方法 + .handler(new NettyClientInitializer(this)); + + ChannelFuture channelFuture = bootstrap.connect().sync(); + + channel = channelFuture.channel(); + + //账号登陆 + CmppMessageHeader cmppConnect = new CmppConnect(serviceId, pwd); + channel.writeAndFlush(cmppConnect); + + channelFuture.addListener(ChannelFutureListener.CLOSE_ON_FAILURE); + + //关闭前阻塞 +// channelFuture.channel().closeFuture().sync(); + } +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/NettyClientInitializer.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/NettyClientInitializer.java new file mode 100644 index 0000000..24fc8ca --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/NettyClientInitializer.java @@ -0,0 +1,40 @@ +package com.mashibing.smsgateway.netty4; + +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import io.netty.handler.timeout.IdleStateHandler; + +import java.util.concurrent.TimeUnit; + +/** + * Netty初始化信息,指定好心跳,编解码,响应处理逻辑执行方式 + */ +public class NettyClientInitializer extends ChannelInitializer { + + private NettyClient client; + + public NettyClientInitializer(NettyClient client) { + this.client = client; + } + + @Override + protected void initChannel(SocketChannel ch) { + ChannelPipeline ph = ch.pipeline(); + //长度编码器,防止粘包拆包 + ph.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, -4, 0, true)); + //心跳 + //readerIdleTime:为读超时间(即测试端一定时间内未接收到被测试端消息); + //writerIdleTime:为写超时间(即测试端一定时间内向被测试端发送消息); + //allIdeTime:所有类型的超时时间 + ph.addLast("idleState handler", new IdleStateHandler(0, 0, 20, TimeUnit.SECONDS)); + //心跳包 + ph.addLast("heart handler", new HeartHandler(client)); + //解析 + ph.addLast("encoder", new CMPPEncoder()); + ph.addLast("decoder", new CMPPDecoder()); + //客户端的逻辑 + ph.addLast("cmpp handler", new CMPPHandler()); + } +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/NettyStartCMPP.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/NettyStartCMPP.java new file mode 100644 index 0000000..c22b787 --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/NettyStartCMPP.java @@ -0,0 +1,26 @@ +package com.mashibing.smsgateway.netty4; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + +@Configuration +public class NettyStartCMPP { + + //ip + public static String host = "127.0.0.1"; + //端口 + public static int port = 7890; + //账号 + public static String serviceId = "laozheng"; + //密码 + public static String pwd = "JavaLaoZheng123!"; + + + + @Bean(initMethod = "start") + public NettyClient nettyClient() { + NettyClient cmppClient = new NettyClient(host, port, serviceId, pwd); + return cmppClient; + } +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppActiveTest.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppActiveTest.java new file mode 100644 index 0000000..bcfd1bc --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppActiveTest.java @@ -0,0 +1,26 @@ +package com.mashibing.smsgateway.netty4.entity; + +import com.mashibing.smsgateway.netty4.utils.Command; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +public class CmppActiveTest extends CmppMessageHeader { + + public CmppActiveTest() { + super(Command.CMPP_ACTIVE_TEST, Command.CMPP2_VERSION); + } + + /** + * 实现类必须自定义对象序列化 + * + * @return + */ + @Override + public byte[] toByteArray() { + ByteBuf buf = Unpooled.buffer(12); + buf.writeInt(12); + buf.writeInt(Command.CMPP_ACTIVE_TEST); + buf.writeInt(0); + return buf.array(); + } +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppActiveTestResp.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppActiveTestResp.java new file mode 100644 index 0000000..041d616 --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppActiveTestResp.java @@ -0,0 +1,27 @@ +package com.mashibing.smsgateway.netty4.entity; + +import com.mashibing.smsgateway.netty4.utils.Command; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + + +public class CmppActiveTestResp extends CmppMessageHeader { + public CmppActiveTestResp() { + super(Command.CMPP_ACTIVE_TEST_RESP, Command.CMPP2_VERSION); + } + + /** + * 实现类必须自定义对象序列化 + * + * @return + */ + @Override + public byte[] toByteArray() { + ByteBuf buf = Unpooled.buffer(4 + 4 + 4 + 1); + buf.writeInt(4 + 4 + 4 + 1); + buf.writeInt(Command.CMPP_ACTIVE_TEST_RESP); + buf.writeInt(0); + buf.writeByte(0); + return buf.array(); + } +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppConnect.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppConnect.java new file mode 100644 index 0000000..654e50d --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppConnect.java @@ -0,0 +1,44 @@ +package com.mashibing.smsgateway.netty4.entity; + +import com.mashibing.smsgateway.netty4.utils.Command; +import com.mashibing.smsgateway.netty4.utils.MsgUtils; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +/** + * 与CMPP建立连接需要的信息 + */ +public class CmppConnect extends CmppMessageHeader { + + private String serviceId; + + private String pwd; + + public CmppConnect(String serviceId, String pwd) { + super(Command.CMPP_CONNECT, Command.CMPP2_VERSION); + this.serviceId = serviceId; + this.pwd = pwd; + } + + @Override + public byte[] toByteArray() { + ByteBuf buf = Unpooled.buffer(4 + 4 + 4 + 6 + 16 + 1 + 4); + + //Total_Length + buf.writeInt(4 + 4 + 4 + 6 + 16 + 1 + 4); + //Command_Id + buf.writeInt(Command.CMPP_CONNECT); + //Sequence_Id + buf.writeInt(MsgUtils.getSequence()); + //sourceAddr + buf.writeBytes(MsgUtils.getLenBytes(serviceId, 6)); + //authenticatorSource + buf.writeBytes(MsgUtils.getAuthenticatorSource(serviceId, pwd)); + //version + buf.writeByte(1); + //timestamp + buf.writeInt(Integer.parseInt(MsgUtils.getTimestamp())); + + return buf.array(); + } +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppDeliver.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppDeliver.java new file mode 100644 index 0000000..9814642 --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppDeliver.java @@ -0,0 +1,368 @@ +package com.mashibing.smsgateway.netty4.entity; + +import com.mashibing.smsgateway.netty4.utils.MsgUtils; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; + + +public class CmppDeliver { + + private byte[] Msg_Id = new byte[8]; + private String Dest_Id;// 21 目的号码 String + private String Service_Id;// 10 业务标识 String + private byte TP_pid = 0; + private byte TP_udhi = 0; + private byte Msg_Fmt = 15; + private String Src_terminal_Id;// 21 string 源终端MSISDN号码 + private byte Registered_Delivery = 0;// 是否为状态报告 0:非状态报告1:状态报告 + private byte msg_Length;// 消息长度 + private String msg_Content;// 消息内容 + private long Reserved; // 保留字段 + + /** + * 当ISMG向SP送交状态报告时,信息内容字段(Msg_Content)格式定义如下: + */ + + private long Msg_Id_DELIVRD; + private String Stat; + private String Submit_time; + private String Done_time; + private String Dest_terminal_Id; + private int SMSC_sequence; + + private int result;// 解析结果 + + /** + * 2016年9月30日 + * + * @throws IOException + */ + public CmppDeliver(byte[] data) { + + System.arraycopy(data, 12, data, 0, data.length - 12); + + ByteArrayInputStream bais = null; + DataInputStream dis = null; + + try { + if (null != data && data.length > 0) { + bais = new ByteArrayInputStream(data); + dis = new DataInputStream(bais); + /** + * migid 需要转换 + */ + byte[] msgid_b = new byte[8]; + dis.read(msgid_b); + this.Msg_Id = msgid_b; + this.Dest_Id = MsgUtils.readString(dis, 21, null);// 21bit + this.Service_Id = MsgUtils.readString(dis, 10, null); + this.TP_pid = dis.readByte(); + this.TP_udhi = dis.readByte(); + this.Msg_Fmt = dis.readByte(); + // 源终端MSISDN号码(状态报告时填为CMPP_SUBMIT消息的目的终端号码) + this.Src_terminal_Id = MsgUtils.readString(dis, 21, this.Msg_Fmt == 8 ? "UTF-16BE" : "gb2312"); + // 是否为应答信息 0:非应答信息 1:状态报告 + this.Registered_Delivery = dis.readByte(); + this.msg_Length = dis.readByte(); + // 状态报告的 msg_Content_b 类型大小为协议固定8+7+10+10+21+4 + byte[] msg_Content_b = new byte[this.Registered_Delivery == 0 ? this.msg_Length + : 8 + 7 + 10 + 10 + 21 + 4]; + dis.read(msg_Content_b); + // 如果是状态报告 + if (this.Registered_Delivery == 1) { + ByteArrayInputStream baisd = new ByteArrayInputStream(msg_Content_b); + DataInputStream disd = new DataInputStream(baisd); + // 开始解析 content中的字段 + byte[] Msg_Id_DELIVRD_B = new byte[8]; + disd.read(Msg_Id_DELIVRD_B); + this.Msg_Id_DELIVRD = MsgUtils.bytesToLong(Msg_Id_DELIVRD_B); + this.Msg_Id_DELIVRD = Math.abs(this.Msg_Id_DELIVRD); + this.Stat = MsgUtils.readString(disd, 7, this.Msg_Fmt == 8 ? "UTF-16BE" : "gb2312"); + this.Submit_time = MsgUtils.readString(disd, 10, this.Msg_Fmt == 8 ? "UTF-16BE" : "gb2312"); + this.Done_time = MsgUtils.readString(disd, 10, this.Msg_Fmt == 8 ? "UTF-16BE" : "gb2312"); + this.Dest_terminal_Id = MsgUtils.readString(disd, 21, this.Msg_Fmt == 8 ? "UTF-16BE" : "gb2312"); + this.SMSC_sequence = disd.readInt(); + disd.close(); + baisd.close(); + this.result = 0; + } else { + this.msg_Content = new String(msg_Content_b, this.Msg_Fmt == 8 ? "UTF-16BE" : "gb2312"); + this.Reserved = dis.readLong();// 保留项 暂无用 + } + this.result = 0; + } else { + this.result = 1; + } + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (null != dis) + dis.close(); + if (null != bais) + bais.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + + /** + * @return msg_Id + */ + public byte[] getMsg_Id() { + return Msg_Id; + } + + /** + * @return dest_Id + */ + public String getDest_Id() { + return Dest_Id; + } + + /** + * @return service_Id + */ + public String getService_Id() { + return Service_Id; + } + + /** + * @return tP_pid + */ + public byte getTP_pid() { + return TP_pid; + } + + /** + * @return tP_udhi + */ + public byte getTP_udhi() { + return TP_udhi; + } + + /** + * @return msg_Fmt + */ + public byte getMsg_Fmt() { + return Msg_Fmt; + } + + /** + * @return src_terminal_Id + */ + public String getSrc_terminal_Id() { + return Src_terminal_Id; + } + + /** + * @return registered_Delivery + */ + public byte getRegistered_Delivery() { + return Registered_Delivery; + } + + /** + * @return msg_Length + */ + public byte getMsg_Length() { + return msg_Length; + } + + /** + * @return msg_Content + */ + public String getMsg_Content() { + return msg_Content; + } + + /** + * @return reserved + */ + public long getReserved() { + return Reserved; + } + + /** + * @return msg_Id_DELIVRD + */ + public long getMsg_Id_DELIVRD() { + return Msg_Id_DELIVRD; + } + + /** + * @return stat + */ + public String getStat() { + return Stat; + } + + /** + * @return submit_time + */ + public String getSubmit_time() { + return Submit_time; + } + + /** + * @return done_time + */ + public String getDone_time() { + return Done_time; + } + + /** + * @return dest_terminal_Id + */ + public String getDest_terminal_Id() { + return Dest_terminal_Id; + } + + /** + * @return sMSC_sequence + */ + public int getSMSC_sequence() { + return SMSC_sequence; + } + + /** + * @return result + */ + public int getResult() { + return result; + } + + /** + * @param msg_Id 要设置的 msg_Id + */ + public void setMsg_Id(byte[] msg_Id) { + Msg_Id = msg_Id; + } + + /** + * @param dest_Id 要设置的 dest_Id + */ + public void setDest_Id(String dest_Id) { + Dest_Id = dest_Id; + } + + /** + * @param service_Id 要设置的 service_Id + */ + public void setService_Id(String service_Id) { + Service_Id = service_Id; + } + + /** + * @param tP_pid 要设置的 tP_pid + */ + public void setTP_pid(byte tP_pid) { + TP_pid = tP_pid; + } + + /** + * @param tP_udhi 要设置的 tP_udhi + */ + public void setTP_udhi(byte tP_udhi) { + TP_udhi = tP_udhi; + } + + /** + * @param msg_Fmt 要设置的 msg_Fmt + */ + public void setMsg_Fmt(byte msg_Fmt) { + Msg_Fmt = msg_Fmt; + } + + /** + * @param src_terminal_Id 要设置的 src_terminal_Id + */ + public void setSrc_terminal_Id(String src_terminal_Id) { + Src_terminal_Id = src_terminal_Id; + } + + /** + * @param registered_Delivery 要设置的 registered_Delivery + */ + public void setRegistered_Delivery(byte registered_Delivery) { + Registered_Delivery = registered_Delivery; + } + + /** + * @param msg_Length 要设置的 msg_Length + */ + public void setMsg_Length(byte msg_Length) { + this.msg_Length = msg_Length; + } + + /** + * @param msg_Content 要设置的 msg_Content + */ + public void setMsg_Content(String msg_Content) { + this.msg_Content = msg_Content; + } + + /** + * @param reserved 要设置的 reserved + */ + public void setReserved(long reserved) { + Reserved = reserved; + } + + /** + * @param msg_Id_DELIVRD 要设置的 msg_Id_DELIVRD + */ + public void setMsg_Id_DELIVRD(int msg_Id_DELIVRD) { + Msg_Id_DELIVRD = msg_Id_DELIVRD; + } + + /** + * @param stat 要设置的 stat + */ + public void setStat(String stat) { + Stat = stat; + } + + /** + * @param submit_time 要设置的 submit_time + */ + public void setSubmit_time(String submit_time) { + Submit_time = submit_time; + } + + /** + * @param done_time 要设置的 done_time + */ + public void setDone_time(String done_time) { + Done_time = done_time; + } + + /** + * @param dest_terminal_Id 要设置的 dest_terminal_Id + */ + public void setDest_terminal_Id(String dest_terminal_Id) { + Dest_terminal_Id = dest_terminal_Id; + } + + /** + * @param sMSC_sequence 要设置的 sMSC_sequence + */ + public void setSMSC_sequence(int sMSC_sequence) { + SMSC_sequence = sMSC_sequence; + } + + /** + * @param result 要设置的 result + */ + public void setResult(int result) { + this.result = result; + } + +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppMessageHeader.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppMessageHeader.java new file mode 100644 index 0000000..54882cf --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppMessageHeader.java @@ -0,0 +1,43 @@ +package com.mashibing.smsgateway.netty4.entity; + +import java.io.Serializable; + + +public abstract class CmppMessageHeader implements Serializable { + + /** + * 消息总长度(含消息头及消息体) + */ + protected int totalLength; + + /** + * 命令标识 + */ + protected int commandId; + + /** + * 消息流水号,顺序累加,步长为1,循环使用(一对请求和应答消息的流水号必须相同) + */ + protected long sequenceId; + + /** + * CMPP版本 2.0或 3.0 + */ + protected byte version; + + + protected CmppMessageHeader(int commandId, byte version) { + this.commandId = commandId; + this.version = version; + } + + /** + * 实现类必须自定义对象序列化 + * + * @return + */ + public abstract byte[] toByteArray(); + + +} + diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppSubmit.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppSubmit.java new file mode 100644 index 0000000..4341eb0 --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppSubmit.java @@ -0,0 +1,148 @@ +package com.mashibing.smsgateway.netty4.entity; + +import com.mashibing.smsgateway.netty4.utils.Command; +import com.mashibing.smsgateway.netty4.utils.MsgUtils; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +import java.io.UnsupportedEncodingException; + +/** + * CMPP请求信息 + */ +/** + * CMPP请求信息 + */ +public class CmppSubmit extends CmppMessageHeader { + + int msgId = 0; + + byte pkTotal = 0; + + byte pkNumber = 0; + + byte registeredDelivery = 1; + + byte msgLevel = 0; + + String serviceId;// 10位长度 + + byte feeUserType = 3; + + String feeTerminalId;// 21位长度 + + byte feeTerminalType = 0; + + byte tp_pid = 0; + + byte tp_udhi = 0; + + /** + * 0:ASCII串 + * 3:短信写卡操作 + * 4:二进制信息 + * 8:UCS2编码 + * 15:含GB汉字 + */ + byte msgFmt = 8; + + String msgSrc;// 6位长度 + + /** + * 02:对“计费用户号码”按条计信息费 + * 03:对“计费用户号码”按包月收取信息费 + * 04:对“计费用户号码”的信息费封顶 + * 05:对“计费用户号码”的收费是由SP实现 + */ + String feeType;// 2位长度 + + String feeCode;// 6位长度 + + String vaildTime = "";// 17位长度 + + String atTime = "";// 17位长度 + + String srcId;// 21位长度 + + byte destUsrTl = 1; + + String destTerminalId;// 21位长度 + + byte destTerminalType = 0; + + byte msgLength; // 1位长度 + + byte[] msgContent; + + String linkId = "";// 保留字 + + private int terminalIdLen; + private int linkIdLen; + private int submitExpMsgLen; + + public CmppSubmit(byte version, String srcId, int SequenceId, String mobile, String content) { + super(Command.CMPP_SUBMIT, version); + if (version == Command.CMPP2_VERSION) { + terminalIdLen = 21; + linkIdLen = 8; + submitExpMsgLen = Command.CMPP2_SUBMIT_LEN_EXPMSGLEN; + } else { + terminalIdLen = 32; + linkIdLen = 20; + submitExpMsgLen = Command.CMPP3_SUBMIT_LEN_EXPMSGLEN; + } + + this.feeTerminalId = ""; + this.feeType = "02"; + this.feeCode = "000000"; + this.srcId = srcId + "1630"; + this.msgFmt = (byte) 8; + this.linkId = ""; + try { + msgContent = content.getBytes("UTF-16BE"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + this.msgId = SequenceId; + this.sequenceId = this.msgId; + this.destTerminalId = mobile; + } + + + @Override + public byte[] toByteArray() { + + ByteBuf buf = Unpooled.buffer(130 + 8 + ((byte) 1) * 21 + msgContent.length); + buf.writeInt(130 + 8 + ((byte) 1) * 21 + msgContent.length); + buf.writeInt(commandId); + buf.writeInt(msgId); + + buf.writeLong(0); + buf.writeByte(0); + buf.writeByte(0); + buf.writeByte(1); + buf.writeByte(0); + buf.writeBytes(MsgUtils.getLenBytes(serviceId, 10)); + buf.writeByte((byte) 2); + buf.writeBytes(MsgUtils.getLenBytes("", 21)); + buf.writeByte(0); + buf.writeByte(0); + buf.writeByte(8); + + buf.writeBytes(MsgUtils.getLenBytes(serviceId, 6)); + buf.writeBytes(MsgUtils.getLenBytes(feeType, 2)); + buf.writeBytes(MsgUtils.getLenBytes(feeCode, 6)); + buf.writeBytes(MsgUtils.getLenBytes(vaildTime, 17)); + buf.writeBytes(MsgUtils.getLenBytes(atTime, 17)); + buf.writeBytes(MsgUtils.getLenBytes(srcId, 21)); + buf.writeByte((byte) 1); + buf.writeBytes(MsgUtils.getLenBytes(destTerminalId, 21)); + buf.writeByte(msgContent.length); + buf.writeBytes(msgContent); + buf.writeLong((long) 0); + + return buf.array(); + } + + +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppSubmitResp.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppSubmitResp.java new file mode 100644 index 0000000..0e914da --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/entity/CmppSubmitResp.java @@ -0,0 +1,38 @@ +package com.mashibing.smsgateway.netty4.entity; + + +import com.mashibing.smsgateway.netty4.utils.MsgUtils; +import org.apache.commons.lang3.ArrayUtils; + + +/** + * CMPP响应信息 + */ +public class CmppSubmitResp { + + private int sequenceId; + + private int result; + + private long msgId; + + public CmppSubmitResp(byte[] bytes) { + this.sequenceId = MsgUtils.bytesToInt(ArrayUtils.subarray(bytes, 8, 12)); + this.msgId = MsgUtils.bytesToLong(ArrayUtils.subarray(bytes, 12, 20)); + this.msgId = Math.abs(this.msgId); + this.result = bytes[20]; + } + + public int getResult() { + return result; + } + + public long getMsgId() { + return msgId; + } + + public int getSequenceId() { + return sequenceId; + } + +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/utils/Command.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/utils/Command.java new file mode 100644 index 0000000..27779d9 --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/utils/Command.java @@ -0,0 +1,155 @@ +package com.mashibing.smsgateway.netty4.utils; + +/** + * 以下常量均为CMPP2.0协议中规定的值 + */ +public interface Command { + /** + * 请求连接 + */ + public final int CMPP_CONNECT = 0x00000001; + /** + * 请求连接应答 + */ + public final int CMPP_CONNECT_RESP = 0x80000001; + /** + * 终止连接 + */ + public final int CMPP_TERMINATE = 0x00000002; + /** + * 终止连接应答 + */ + public final int CMPP_TERMINATE_RESP = 0x80000002; + /** + * 提交短信 + */ + public final int CMPP_SUBMIT = 0x00000004; + /** + * 提交短信应答 + */ + public final int CMPP_SUBMIT_RESP = 0x80000004; + /** + * 短信下发 + */ + public final int CMPP_DELIVER = 0x00000005; + /** + * + 下发短信应答 + */ + public final int CMPP_DELIVER_RESP = 0x80000005; + /** + * 发送短信状态查询 + */ + public final int CMPP_QUERY = 0x00000006; + /** + * 发送短信状态查询应答 + */ + public final int CMPP_QUERY_RESP = 0x80000006; + /** + * 删除短信 + */ + public final int CMPP_CANCEL = 0x00000007; + /** + * 删除短信应答 + */ + public final int CMPP_CANCEL_RESP = 0x80000007; + /** + * 激活测试 + */ + public final int CMPP_ACTIVE_TEST = 0x00000008; + /** + * 激活测试应答 + */ + public final int CMPP_ACTIVE_TEST_RESP = 0x80000008; + /** + * 消息前转 + */ + public final int CMPP_FWD = 0x00000009; + /** + * 消息前转应答 + */ + public final int CMPP_FWD_RESP = 0x80000009; + /** + * MT路由请求 + */ + public final int CMPP_MT_ROUTE = 0x00000010; + /** + * MT路由请求应答 + */ + public final int CMPP_MT_ROUTE_RESP = 0x80000010; + /** + * MO路由请求 + */ + public final int CMPP_MO_ROUTE = 0x00000011; + /** + * MO路由请求应答 + */ + public final int CMPP_MO_ROUTE_RESP = 0x80000011; + /** + * 获取MT路由请求 + */ + public final int CMPP_GET_MT_ROUTE = 0x00000012; + /** + * 获取MT路由请求应答 + */ + public final int CMPP_GET_MT_ROUTE_RESP = 0x80000012; + /** + * MT路由更新 + */ + public final int CMPP_MT_ROUTE_UPDATE = 0x00000013; + /** + * MT路由更新应答 + */ + public final int CMPP_MT_ROUTE_UPDATE_RESP = 0x80000013; + /** + * MO路由更新 + */ + public final int CMPP_MO_ROUTE_UPDATE = 0x00000014; + /** + * MO路由更新应答 + */ + public final int CMPP_MO_ROUTE_UPDATE_RESP = 0x80000014; + /** + * MT路由更新 + */ + public final int CMPP_PUSH_MT_ROUTE_UPDATE = 0x00000015; + /** + * MT路由更新应答 + */ + public final int CMPP_PUSH_MT_ROUTE_UPDATE_RESP = 0x80000015; + /** + * MO路由更新 + */ + public final int CMPP_PUSH_MO_ROUTE_UPDATE = 0x00000016; + /** + * MO路由更新应答 + */ + public final int CMPP_PUSH_MO_ROUTE_UPDATE_RESP = 0x80000016; + /** + * 获取MO路由请求 + */ + public final int CMPP_GET_MO_ROUTE = 0x00000017; + /** + * 获取MO路由请求应答 + */ + public final int CMPP_GET_MO_ROUTE_RESP = 0x80000017; + + /** + * Cmpp协议版本字节常量 + */ + public static final byte CMPP2_VERSION = (byte) 32; + /** + * Cmpp协议版本字节常量 + */ + public static final byte CMPP3_VERSION = (byte) 48; + + /** + * 下行长度(不包含短信内容长度) + */ + public static final int CMPP2_SUBMIT_LEN_EXPMSGLEN = 8 + 1 + 1 + 1 + 1 + 10 + 1 + 21 + 1 + 1 + 1 + + 6 + 2 + 6 + 17 + 17 + 21 + 1 + 1 + 8; + + public static final int CMPP3_SUBMIT_LEN_EXPMSGLEN = 8 + 1 + 1 + 1 + 1 + 10 + 1 + 32 + 1 + 1 + + 1 + 1 + 6 + 2 + 6 + 17 + 17 + 21 + 1 + 1 + 1 + 20; + + +} diff --git a/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/utils/MsgUtils.java b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/utils/MsgUtils.java new file mode 100644 index 0000000..77fe567 --- /dev/null +++ b/beacon-smsgateway/src/main/java/com/mashibing/smsgateway/netty4/utils/MsgUtils.java @@ -0,0 +1,216 @@ +package com.mashibing.smsgateway.netty4.utils; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * 解析工具 + */ +public class MsgUtils { + + //序列编号起始值(起始为随机数即可) + private static int sequenceId = Math.abs(new Long(System.currentTimeMillis()).intValue()); + //序列峰值 + private static int MAX_VALUE = Integer.MAX_VALUE / 2; + + /** + * 序列 自增 + */ + public static synchronized int getSequence() { + ++sequenceId; + if (sequenceId > MAX_VALUE) { + sequenceId = Math.abs(new Long(System.currentTimeMillis()).intValue()); + } + return sequenceId; + } + + /** + * 时间戳的明文,由客户端产生,格式为MMDDHHMMSS,即月日时分秒,10位数字的整型,右对齐 �? + */ + public static String getTimestamp() { + DateFormat format = new SimpleDateFormat("MMddhhmmss"); + return format.format(new Date()); + } + + /** + * 用于鉴别源地�?。其值�?�过单向MD5 hash计算得出,表示如下: + * AuthenticatorSource = + * MD5(Source_Addr+9 字节�?0 +shared secret+timestamp�? + * Shared secret 由中国移动与源地�?实体事先商定,timestamp格式为:MMDDHHMMSS,即月日时分秒,10位�?? + * + * @return + */ + public static byte[] getAuthenticatorSource(String spId, String secret) { + try { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + byte[] data = (spId + "\0\0\0\0\0\0\0\0\0" + secret + MsgUtils.getTimestamp()).getBytes(); + return md5.digest(data); + } catch (NoSuchAlgorithmException e) { + System.out.println("SP链接到ISMG拼接AuthenticatorSource失败" + e.getMessage()); + return null; + } + } + + /** + * 向流中写入指定字节长度的字符串,不足时补0 + * + * @param dous:要写入的流对�? + * @param s:要写入的字符�? + * @param len:写入长度,不足�?0 + */ + public static void writeString(DataOutputStream dous, String s, int len) { + + try { + byte[] data = s.getBytes("gb2312"); + if (data.length > len) { + System.out.println("向流中写入的字符串超长!要写" + len + " 字符串是:" + s); + } + int srcLen = data.length; + dous.write(data); + while (srcLen < len) { + dous.write('\0'); + srcLen++; + } + } catch (IOException e) { + System.out.println("向流中写入指定字节长度的字符串失败:" + e.getMessage()); + } + } + + + public static byte[] getLenBytes(String s, int len) { + if (s == null) { + s = ""; + } + byte[] rb = new byte[len]; + byte[] sb = s.getBytes(); + for (int i = sb.length; i < rb.length; i++) { + rb[i] = 0; + } + if (sb.length == len) { + return sb; + } else { + for (int i = 0; i < sb.length && i < len; i++) { + rb[i] = sb[i]; + } + return rb; + } + } + + + /** + * 从流中读取指定长度的字节,转成字符串返回 + * + * @param ins:要读取的流对�? + * @param len:要读取的字符串长�? + * @return:读取到的字符�? + */ + public static String readString(java.io.DataInputStream ins, int len, String charset) { + byte[] b = new byte[len]; + try { + ins.read(b); + String s; + if (charset == null) + s = new String(b); + else + s = new String(b, charset); + s = s.trim(); + return s; + } catch (IOException e) { + return ""; + } + } + + /** + * 截取字节 + * + * @param msg + * @param start + * @param end + * @return + */ + public static byte[] getMsgBytes(byte[] msg, int start, int end) { + byte[] msgByte = new byte[end - start]; + int j = 0; + for (int i = start; i < end; i++) { + msgByte[j] = msg[i]; + j++; + } + return msgByte; + } + + /** + * UCS2解码 + * + * @param src UCS2 源串 + * @return 解码后的UTF-16BE字符�? + */ + public static String DecodeUCS2(String src) { + byte[] bytes = new byte[src.length() / 2]; + for (int i = 0; i < src.length(); i += 2) { + bytes[i / 2] = (byte) (Integer.parseInt(src.substring(i, i + 2), 16)); + } + String reValue = ""; + try { + reValue = new String(bytes, "UTF-16BE"); + } catch (UnsupportedEncodingException e) { + reValue = ""; + } + return reValue; + + } + + /** + * byte[] 转 long + * 2016年9月30日 + */ + public static long bytesToLong(byte[] b) { + long temp = 0; + long res = 0; + for (int i = 0; i < 8; i++) { + temp = b[i] & 0xff; + temp <<= 8 * i; + res |= temp; + } + return res; + } + + public static int bytesToInt(byte[] b) { + return b[3] & 0xFF | + (b[2] & 0xFF) << 8 | + (b[1] & 0xFF) << 16 | + (b[0] & 0xFF) << 24; + } + + + /** + * UCS2编码 + * + * @param src UTF-16BE编码的源�? + * @return 编码后的UCS2�? + */ + public static String EncodeUCS2(String src) { + byte[] bytes; + try { + bytes = src.getBytes("UTF-16BE"); + } catch (UnsupportedEncodingException e) { + bytes = new byte[0]; + } + StringBuffer reValue = new StringBuffer(); + StringBuffer tem = new StringBuffer(); + for (int i = 0; i < bytes.length; i++) { + tem.delete(0, tem.length()); + tem.append(Integer.toHexString(bytes[i] & 0xFF)); + if (tem.length() == 1) { + tem.insert(0, '0'); + } + reValue.append(tem); + } + return reValue.toString().toUpperCase(); + } +}