import io.netty.bootstrap.Bootstrap;
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.nio.NioDatagramChannel;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.Executors;
@Component
public class UdpClient implements CommandLineRunner {
private Logger logger = LoggerFactory.getLogger("udp");
@Autowired
@Setter
private UdpServerHandler udpServerHandler;
@Value("${udp.port}")
private int port;
public void startClient(int port) throws Exception {
try {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(udpServerHandler);
b.bind(port).sync().channel().closeFuture().sync();
logger.info("启动udp,端口:{}", port);
} finally {
group.shutdownGracefully();
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run(String... args) throws Exception {
UdpClient that = this;
Executors.newSingleThreadScheduledExecutor().execute(() -> {
try {
that.startClient(port);
} catch (Exception e) {
e.printStackTrace();
}
});
logger.info("启动udp完成,端口:{}",port);
}
}
import com.jzxs.transmissionmonitor.manager.udp.SocketIOWriter;
import com.jzxs.transmissionmonitor.manager.udp.utils.ByteUtil;
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.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.net.InetSocketAddress;
/**
* @author zj
* @version 1.0
* @functin
* @date 2020/11/2 17:00
*/
@Component
public class UdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
private static Logger logger = LoggerFactory.getLogger("udp");
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//ctx.close();
cause.printStackTrace();
logger.info("未知错误:{}", cause.getMessage());
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, DatagramPacket datagramPacket) {
String deviceId = "";
try {
InetSocketAddress sender = datagramPacket.sender();
ByteBuf content = datagramPacket.copy().content();
//读数据
byte[] read = new byte[content.readableBytes()];
content.readBytes(read);
//接收报文
String packet = ByteUtil.BinaryToHexString(read).toUpperCase();
String response="";//返回报文
SocketIOWriter.udpWriteAndFlus(channelHandlerContext.channel(), response, datagramPacket);
ReferenceCountUtil.release(content);
} catch (Exception e) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(baos));
String exception = baos.toString();
logger.info("设备{},未知错误:{}", deviceId, exception);
}
}
}
public class SocketIOWriter {
public static void udpWriteAndFlus(Channel channel,String msg,DatagramPacket datagramPacket){
byte[] bytes = ByteUtil.hexStringToBytes(msg);
ByteBuf buffer = channel.alloc().buffer();
buffer = buffer.writeBytes(bytes);
channel.writeAndFlush(new DatagramPacket(buffer,datagramPacket.sender()));
}
public static void udpWriteAndFlus(Channel channel,String msg,InetSocketAddress sender){
byte[] bytes = ByteUtil.hexStringToBytes(msg);
ByteBuf buffer = channel.alloc().buffer();
buffer = buffer.writeBytes(bytes);
channel.writeAndFlush(new DatagramPacket(buffer,sender));
}
}
另外,很多时候都 需要在通过接口来指定某个udp端发送报文。这里我们需要先将UdpServerHandler.channelRead0()中datagramPacket.sender()和channelHandlerContext.channel()返回的对象在全局缓存起来。然后调用udpWriteAndFlus(Channel channel,String msg,DatagramPacket datagramPacket),即可向指定udp端发送数据。