首先引入依赖
<!--netty依赖-->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.74.Final</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.20</version>
</dependency>
package com.bw.edgeagent.test;
import java.net.InetSocketAddress;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.ObjectUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
/**
* @Author mxf
* @Description 客户端连接
* @Date 2023/5/10 9:29
* @Param
* @return
**/
public class BootNettyUdpClient {
public void bind(String address, int port, Object msg) {
ByteBuf data = (ByteBuf) msg;
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap clientBootstrap = new Bootstrap();
clientBootstrap = clientBootstrap.group(eventLoopGroup);
clientBootstrap = clientBootstrap.channel(NioDatagramChannel.class);
clientBootstrap = clientBootstrap.option(ChannelOption.SO_BROADCAST, true);
clientBootstrap = clientBootstrap.handler(new BootNettyUdpHandler());
Channel channel = clientBootstrap.bind(61005).sync().channel();
//channel.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(data, CharsetUtil.UTF_8), new InetSocketAddress(address,port))).sync();
channel.writeAndFlush(new DatagramPacket(data, new InetSocketAddress(address,port))).sync();
// 与BootNettyUdpClientSimpleChannelInboundHandler中的ctx.channel().id().toString()是一样的值
System.out.println("channel_id = "+channel.id().toString());
// 方式一:查询等待超时 单位s 等待服务端原路返回的消息,
// 在channelRead0(ChannelHandlerContext ctx, DatagramPacket msg)方法中收到消息后可主动关闭channel,此处等待自然释放
//channel.closeFuture().await(10000);
// 方式二:直接等待服务端原路返回后在channelRead0(ChannelHandlerContext ctx, DatagramPacket msg)方法中收到消息后可主动关闭channe
// 若服务端没有原路返回消息或者消息未收到将会一直等待,浪费资源
channel.closeFuture().sync();
} catch (Exception e) {
// TODO: handle exception
} finally {
System.out.println("netty client udp close!");
eventLoopGroup.shutdownGracefully();
}
}
// 测试
public static void main(String[] args) {
// 向网段内的所有机器广播UDP消息,这个没试过是不是这个原理
// new BootNettyUdpClient().bind("255.255.255.255",9999,"I am client");
//String hexStr = "17 20 00 00 25 53 02 1B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
String hexStr = "17 80 00 00 25 53 02 1B 01 01 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
ByteBuf byteBufMsg = getByteBuf(hexStr);
// 指定某个套接字地址和发送的内容可以发送消息
// 该方式也可以封装成一个udp的客户端的send类
new BootNettyUdpClient().bind("10.1.77.180",60000,byteBufMsg);
}
/**
* @return io.netty.buffer.ByteBuf
* @Author Mxf
* @Date 2022/4/15 11:57
* @Description decodeHex 编码 艾礼安电子围栏主机服务端通过十六进制数据交互
* @Param [command]
**/
private static ByteBuf getByteBuf(Object command) {
String msg = ObjectUtil.toString(command);
byte[] data = HexUtil.decodeHex(msg);
ByteBuf byteBufMsg = Unpooled.buffer();
byteBufMsg.writeBytes(data);
return byteBufMsg;
}
}
package com.bw.edgeagent.test;
import cn.hutool.core.util.HexUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.CharsetUtil;
/**
* @Author mxf
* @Description 消息处理类
* @Date 2023/5/10 9:30
* @Param
* @return
**/
public class BootNettyUdpHandler extends SimpleChannelInboundHandler<DatagramPacket> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
try {
String strData = msg.content().toString(CharsetUtil.UTF_8);
System.out.println("msg1111111111---"+ strData);
//打印收到的消息
System.out.println("msg222222222---"+ getHexString(msg.content()));
// 与BootNettyUdpClient中的channel.id().toString()是一样的值
System.out.println(ctx.channel().id().toString());
// 收到服务端原路返回的消息后,不需要再次向服务端发送消息, 可以在这里暴力关闭,也可以在 channelReadComplete(ChannelHandlerContext ctx)内
// ctx.close();
} catch (Exception e) {
System.out.println(e.toString());
}
}
/**
* @return java.lang.String
* @Author Mxf
* @Date 2022/4/15 11:54
* @Description 艾礼安电子围栏返回的是十六进制数据 解码 十六进制数据转成字符串
* @Param [msg]
**/
private String getHexString(Object msg) {
ByteBuf buf = (ByteBuf) msg;
byte[] con = new byte[buf.readableBytes()];
buf.readBytes(con);
return HexUtil.encodeHexStr(con);
}
/**
* 重写方法
* 结构:
* 1.public class BootNettyUdpHandler extends SimpleChannelInboundHandler<DatagramPacket>
*
* 2.public abstract class SimpleChannelInboundHandler<I> extends ChannelInboundHandlerAdapter
*
* 3.public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler
*
* ChannelInboundHandlerAdapter类有诸多方法可以重写,可以根据具体需求来写
*
*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
super.channelReadComplete(ctx);
System.out.println("关闭channel");
ctx.close();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}