创建Netty收发线程池,配置监听端口,配置服务实现类。
Config.nNettyPort 自定义监听端口
public class ServerThread extends Thread
{
/**定义一个map,key存放loginCode,value存放ctx**/
//保证线程安全使用ConcurrentHashMap
//public static ConcurrentHashMap <ChannelHandlerContext, DTU> mapDtu = new ConcurrentHashMap<>();
public void run()
{
//boss线程监听端口,worker线程负责数据读写
EventLoopGroup boss = new NioEventLoopGroup(); // 一组线程负责用于处理Client端的连接请求
EventLoopGroup worker = new NioEventLoopGroup(); // 另一组线程负责信息的交互
try
{
ServerBootstrap bootstrap = new ServerBootstrap(); // 辅助工具类,用于服务器通道的一系列配置
//设置线程池
bootstrap.group(boss, worker);
//设置socket工厂
bootstrap.channel(NioServerSocketChannel.class);
//设置管道工厂
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//获取管道
ChannelPipeline pipeline = socketChannel.pipeline();
//处理类
pipeline.addLast(new DTUFrameHandler());
}
});
//设置TCP参数
//1.链接缓冲池的大小(ServerSocketChannel的设置)
bootstrap.option(ChannelOption.SO_BACKLOG, Config.nNettyBacklog);
//bootstrap.option(ChannelOption.SO_SNDBUF, Config.nNettySendBuf);
//bootstrap.option(ChannelOption.SO_RCVBUF, Config.nNettyRcvBuf);
//维持链接的活跃,清除死链接(SocketChannel的设置)
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
//关闭延迟发送
bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
//绑定端口
ChannelFuture cf1 = bootstrap.bind(Config.nNettyPort).sync();
//等待服务端监听端口关闭
cf1.channel().closeFuture().sync(); // 等待关闭,异步,阻塞当前线程
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
//优雅退出,释放线程池资源
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}
DTUFrameHandler 服务实现类(接收设备心跳、返回信息)
public class DTUFrameHandler extends ChannelInboundHandlerAdapter
{
//key: channel id
@Override
public void channelActive(ChannelHandlerContext ctx)
{
DTU.printChannelMessage(ctx,"New client connected");
}
@Override
public void channelRead (final ChannelHandlerContext ctx, Object msg)
{
ByteBuf buf = (ByteBuf) msg;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
//释放内存数据
buf.release();
String channel_id = DTU.getChannelId(ctx);
DTU.printChannelMessage(ctx,channel_id + " Read data:[" + ToHex.ToHex(req) + "]");
}
/** 连接中断,去除ctxMap中相应的ctx**/
@Override
public void channelInactive(ChannelHandlerContext ctx)
{
DTU.printChannelMessage(ctx, "Client disconnected");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable t)
{
DTU.printChannelMessage(ctx, "Client exception");
}
根据所需创建发送信息
cmd.sendDate 根据设备实际情况创建要发送的指令
ctx.channel().writeAndFlush(Unpooled.copiedBuffer(cmd.sendData));
String str_command = " data:[" + ToHex.ToHex(cmd.sendData)+ "]";
DTU.printChannelMessage(ctx,str_command);
pom以及工具类
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
<version>3.10.5.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.42.Final</version>
</dependency>
static char[] BCDCode=new char[]{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','0'};
public static String ToHex(byte[] bytes)
{
int[] read_ints = new int[bytes.length];
for (int i = 0; i < bytes.length; i++) {
if ((int) bytes[i] > 0) {
read_ints[i] = (int) bytes[i];
} else {
read_ints[i] = (int) bytes[i] + 256;
}
}
//System.out.println(Arrays.toString(read_ints));
String str_addr = "";
String EachByteAddress;
for (int addr_b : read_ints) {
EachByteAddress = BCDCode[addr_b / 16]+""+ BCDCode[addr_b % 16] +" ";
str_addr =str_addr + EachByteAddress;
}
return str_addr;
}
public static String getChannelId(ChannelHandlerContext ctx)
{
return ctx.channel().id().toString();
}
收发信息如下
新连接进来创建ctx通道,携带心跳信息。
发送指令
回收信息