文章目录
- 简述
- Netty-UDP集成
- pom引入
- Client
- Handler
- 调用
- 消息发送与接收
- 在线UDP服务
- 系统调用
简述
最近在一些场景中需要使用UDP客户端进行,所以开始集成新的东西。本文集成了一个基于netty的SpringBoot的简单的应用场景。
Netty-UDP集成
pom引入
<!-- netty -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.84.Final</version>
</dependency>
如果项目本身使用redis,则redis默认会集成,我的项目中默认有netty-4.1.84.Final
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Client
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
* @author fir
*/
@Slf4j
@Component
public class LogPushUdpClient implements ApplicationRunner {
private final Bootstrap bootstrap;
public final NioEventLoopGroup workerGroup;
public static Channel channel;
@Override
public void run(ApplicationArguments args) {
start();
}
public void start() {
try {
log.info("UDP客户端--启动");
channel = bootstrap
.bind(1234)
.sync()
.channel();
channel.closeFuture().await(1000);
} catch (InterruptedException e) {
log.info("UDP客户端启动失败");
}
}
private LogPushUdpClient() {
bootstrap = new Bootstrap();
workerGroup = new NioEventLoopGroup();
bootstrap.group(workerGroup)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(new ChannelInitializer<NioDatagramChannel>() {
@Override
protected void initChannel(NioDatagramChannel ch) {
// 获取了通道的管道,管道是一个处理网络事件和操作的处理器链。
ChannelPipeline pipeline = ch.pipeline();
// 向管道添加了自定义的 LogPushUdpClientHandler 处理器,它将处理网络 I/O 事件和数据
pipeline.addLast(new LogPushUdpClientHandler());
}
});
}
}
Handler
package com.fir.home.handler.udp;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.concurrent.GenericFutureListener;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import lombok.extern.slf4j.Slf4j;
/**
* @author fir
*/
@Slf4j
public class LogPushUdpClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
public static HashMap<Long, Boolean> treedMap = new HashMap<>();
/**
* 客户端初次连接时执行的方法
*
* @param ctx 通道处理上下文
*/
@Override
public void channelActive(ChannelHandlerContext ctx) {
log.info("客户端通道已就绪!");
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
final ByteBuf buf = packet.content();
int readableBytes = buf.readableBytes();
byte[] content = new byte[readableBytes];
buf.readBytes(content);
String serverMessage = new String(content);
log.info("[UDP客户端]接受消息: " + serverMessage);
}
/**
* 向服务器发送消息
*
* @param msg 按规则拼接的消息串
* @param inetSocketAddress 目标服务器地址
*/
public static void sendMessage(final String msg, final InetSocketAddress inetSocketAddress) {
log.info("[UDP客户端]发送消息消息: " + msg);
if (msg == null) {
throw new NullPointerException("[UDP客户端]发送数据为空");
}
DatagramPacket datagramPacket = datagramPacket(msg, inetSocketAddress);
senderInternal(datagramPacket);
}
/**
* 组装数据包
*
* @param msg 消息串
* @param inetSocketAddress 服务器地址
* @return DatagramPacket
*/
public static DatagramPacket datagramPacket(String msg, InetSocketAddress inetSocketAddress) {
DatagramPacket datagramPacket;
ByteBuf dataBuf = Unpooled.copiedBuffer(msg, StandardCharsets.UTF_8);
datagramPacket = new DatagramPacket(dataBuf, inetSocketAddress);
return datagramPacket;
}
/**
* 发送数据包服务器无返回结果
*
* @param datagramPacket 数据报文包
*/
private static void senderInternal(final DatagramPacket datagramPacket) {
if (LogPushUdpClient.channel != null) {
LogPushUdpClient.channel.writeAndFlush(datagramPacket).addListener((GenericFutureListener<ChannelFuture>) future -> {
boolean success = future.isSuccess();
if (log.isInfoEnabled()) {
log.info("[UDP客户端]发送结果 : " + success);
}
});
} else {
throw new NullPointerException("UPD上下文通道为空");
}
}
}
调用
InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 50000);
LogPushUdpClientHandler.sendMessage("hello", inetSocketAddress);
消息发送与接收
在线UDP服务
服务端可以使用在线UDP服务
http://udp.xnkiot.com/
系统调用
调用后,可以看到,数据发送成功,并且接受成功。