TCP 服务端 数据解码

This commit is contained in:
haozq 2024-07-31 09:35:32 +08:00
parent 94f0251ca0
commit e13552b692
14 changed files with 339 additions and 13 deletions

12
pom.xml
View File

@ -76,6 +76,18 @@
<artifactId>mapper</artifactId>
<version>4.1.5</version>
</dependency>
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.68.Final</version>
</dependency>
<!-- poi -->
<dependency>
<groupId>org.apache.poi</groupId>

View File

@ -8,12 +8,14 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* @author 黑子
*/
@MapperScan({"com.bonus.aqd.*.*.dao", "com.bonus.aqd.*.dao"})
@SpringBootApplication(exclude={MongoAutoConfiguration.class})
@EnableAsync
public class SpringBootSecurityApplication implements CommandLineRunner {

View File

@ -0,0 +1,32 @@
package com.bonus.aqd.base.dao;
import com.bonus.aqd.base.entity.DevVO;
import org.springframework.stereotype.Repository;
/**
* @author 黑子
*/
@Repository(value = "DevDataMapper")
public interface DevDataMapper {
/**
* 更新双沟状态
* @param devVO
*/
void updateData(DevVO devVO);
/**
* 更新在线状态
* @param devVO
*/
void updateDevStatus(DevVO devVO);
/**
* 更新在线状态
* @param devVO
*/
void downDevStatus(DevVO devVO);
}

View File

@ -0,0 +1,33 @@
package com.bonus.aqd.base.entity;
import lombok.Data;
/**
* 设备实体类
* @author 黑子
*/
@Data
public class DevVO {
private String devCode;
private String devA;
private String devB;
private String devStatus;
private String devAtime;
private String devBtime;
private String startTime;
private String devTime;
/**
* 通道id
*/
private String channId;
}

View File

@ -1,10 +1,16 @@
package com.bonus.aqd.tcpservice;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.net.InetSocketAddress;
@ -13,8 +19,16 @@ import java.net.InetSocketAddress;
* @author 黑子
*/
@ChannelHandler.Sharable
@Component
@Slf4j
public class BootNettyChannelInboundHandlerAdapter extends ChannelInboundHandlerAdapter {
public SaveDataService service = SpringUtils.getBean(SaveDataService.class);
/**
* 注册时执行
*/
@ -22,7 +36,7 @@ public class BootNettyChannelInboundHandlerAdapter extends ChannelInboundHandler
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
//注册通道
super.channelRegistered(ctx);
System.out.println("--channelRegistered--" + ctx.channel().id().toString());
System.out.println("--通道号注册--" + ctx.channel().id().toString());
}
/**
@ -32,7 +46,8 @@ public class BootNettyChannelInboundHandlerAdapter extends ChannelInboundHandler
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
//通道离线
super.channelUnregistered(ctx);
System.out.println("--channelUnregistered--" + ctx.channel().id().toString());
System.out.println("--通道号离线--" + ctx.channel().id().toString());
service.downDevStatus(ctx.channel().id().toString());
}
/**
@ -44,18 +59,24 @@ public class BootNettyChannelInboundHandlerAdapter extends ChannelInboundHandler
if (msg == null) {
return;
}
ByteBuf in = (ByteBuf) msg;
byte[] bs = new byte[in.readableBytes()];
in.readBytes(bs);
String order = ByteUtil.bytesToHexString(bs);
service.addDataInfo(order.trim());
//转成String
String data = (String) msg;
String data =order;
//替换掉 换行 空格
data = data.replaceAll("\r|\n", "");
//获取通道ID 并打印
String channelId = ctx.channel().id().toString();
System.out.println("channelId=" + channelId + "data=" + data);
System.err.println("通道号---> " + channelId + "--->数据---> " + data);
// 这里我将通道id作为code来使用实际是需要msg里来摘取的客户端数据里的唯一值的
// 如果没有则创建 如果有更新data值
BootNettyChannel b = BootNettyChannelCache.get("server:" + channelId);
if (b == null) {
// 第一次更新状态
service.updateDataStatus(order.trim(),channelId);
//创建通道
BootNettyChannel bnc = new BootNettyChannel();
bnc.setChannel(ctx.channel());

View File

@ -29,9 +29,11 @@ public class BootNettyChannelInitializer<SocketChannel> extends ChannelInitializ
ch.pipeline().addLast(new IdleStateHandler(READ_TIME_OUT, WRITE_TIME_OUT, ALL_TIME_OUT, TimeUnit.SECONDS));
// 带编码
ch.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
ch.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
// ch.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
// ch.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
// 在Netty的pipeline中添加
ch.pipeline().addLast(new HexDecoder());
// ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));
// // ChannelOutboundHandler依照逆序执行
// ch.pipeline().addLast("encoder", new StringEncoder());
//

View File

@ -9,7 +9,7 @@ import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
*
* 蚂蚁舞
* @author 黑子
*/
public class BootNettyServer {

View File

@ -0,0 +1,34 @@
package com.bonus.aqd.tcpservice;
/**
* @author 黑子
*/
public class ByteUtil {
public static byte[] hexString2Bytes(String src) {
int l = src.length() / 2;
byte[] ret = new byte[l];
for (int i = 0; i < l; i++) {
ret[i] = (byte) Integer.valueOf(src.substring(i * 2, i * 2 + 2), 16).byteValue();
}
return ret;
}
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
}

View File

@ -0,0 +1,20 @@
package com.bonus.aqd.tcpservice;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
public class HexDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
ByteBuf buffer = ctx.alloc().buffer();
while (in.isReadable()) {
byte b = in.readByte();
buffer.writeBytes(new byte[]{b});
}
out.add(buffer);
}
}

View File

@ -4,9 +4,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
/**
* @author 黑子
*/
@Slf4j
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
/**

View File

@ -0,0 +1,25 @@
package com.bonus.aqd.tcpservice;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* @author 黑子
*/
@Component
public class ServerHandler extends IoHandlerAdapter {
@Autowired
protected SaveDataService service;
private static ServerHandler serverHandler ;
@PostConstruct //通过@PostConstruct实现初始化bean之前进行的操作
public void init() {
serverHandler = this;
serverHandler.service = this.service;
// 初使化时将已静态化的testService实例化
}
}

View File

@ -0,0 +1,114 @@
package com.bonus.aqd.tcpservice;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
/**
* spring工具类 方便在非spring管理环境中获取bean
*
* @author bonus
*/
@Component
public final class SpringUtils implements BeanFactoryPostProcessor
{
/** Spring应用上下文环境 */
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
{
SpringUtils.beanFactory = beanFactory;
}
/**
* 获取对象
*
* @param name
* @return Object 一个以所给名字注册的bean的实例
* @throws BeansException
*
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException
{
return (T) beanFactory.getBean(name);
}
/**
* 获取类型为requiredType的对象
*
* @param clz
* @return
* @throws BeansException
*
*/
public static <T> T getBean(Class<T> clz) throws BeansException
{
T result = (T) beanFactory.getBean(clz);
return result;
}
/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义则返回true
*
* @param name
* @return boolean
*/
public static boolean containsBean(String name)
{
return beanFactory.containsBean(name);
}
/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype 如果与给定名字相应的bean定义没有被找到将会抛出一个异常NoSuchBeanDefinitionException
*
* @param name
* @return boolean
* @throws NoSuchBeanDefinitionException
*
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.isSingleton(name);
}
/**
* @param name
* @return Class 注册对象的类型
* @throws NoSuchBeanDefinitionException
*
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.getType(name);
}
/**
* 如果给定的bean名字在bean定义中有别名则返回这些别名
*
* @param name
* @return
* @throws NoSuchBeanDefinitionException
*
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.getAliases(name);
}
/**
* 获取aop代理对象
*
* @param invoker
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getAopProxy(T invoker)
{
return (T) AopContext.currentProxy();
}
}

View File

@ -37,5 +37,5 @@ zhly:
enable: false
netty:
port: 6665
port: 6666

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bonus.aqd.base.dao.DevDataMapper">
<update id="updateData" parameterType="com.bonus.aqd.base.entity.DevVO">
update tb_device
set dev_a=#{devA} ,dev_b=#{devB}
<if test="devAtime!=null and devAtime!=''">
, dev_a_time=#{devAtime}
</if>
<if test="devBtime!=null and devBtime!=''">
, dev_b_time= #{devBtime}
</if>
,dev_time=now()
where dev_code=#{devCode}
</update>
<update id="updateDevStatus" parameterType="com.bonus.aqd.base.entity.DevVO">
update tb_device
set dev_status=#{devStatus},
<if test="channId!=null and channId!=''">
chann_id= #{channId},
</if>
state_time=now(),
dev_time=now()
where dev_code=#{devCode}
</update>
<update id="downDevStatus" parameterType="com.bonus.aqd.base.entity.DevVO">
update tb_device
set dev_status=0, chann_id= #{channId}
where chann_id=#{channId}
</update>
</mapper>