一、转发服务
1、创建NettyServer,使用线程池实现异步处理
**
* udp服务
*/
public class NettyServer {
private static final Logger LOG = LoggerFactory.getLogger(NettyServer.class);
private final AtomicInteger threadNumber = new AtomicInteger(1);
ThreadPoolExecutor executor = new ThreadPoolExecutor(0, 10, 60,
TimeUnit.SECONDS, new SynchronousQueue<Runnable>()
, r -> new Thread(r,"NettyServer-Thread-" + threadNumber.getAndIncrement()));
@Autowired
NettyServerHandler nettyServerHandler;
public void start(InetSocketAddress address) {
try {
executor.execute(() -> {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioDatagramChannel.class)
// udp协议
.option(ChannelOption.SO_BROADCAST, true)
.handler(nettyServerHandler);
LOG.info("--------------服务端upd服务启动----------------");
ChannelFuture channelFuture = b.bind(address.getAddress(),address.getPort()).sync();
System.out.println("服务器正在监听消息......");
channelFuture.channel().closeFuture().await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
2、创建消息处理类NettyServerHandler
/**
* 消息接收与转发
*/
@Component
public class NettyServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
private static final Logger LOG = LoggerFactory.getLogger(NettyServerHandler.class);
@Value("${nettyClient.ip}")
private String clientIp;
@Value("${nettyClient.port}")
private int clientPort;
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) {
ByteBuf byteBuf = msg.content();
byte[] bytes = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(bytes);
byteBuf = Unpooled.copiedBuffer(new String(bytes).getBytes(StandardCharsets.UTF_8));
LOG.info("接收到消息:" + new String(bytes));
// 将消息转发给客户端
ctx.writeAndFlush(new DatagramPacket(byteBuf, new InetSocketAddress(clientIp, clientPort)));
}
}
3、创建NettyBean用于保存连接上下文
public class NettyBean {
/**
* 保存连接上下文
*/
private Map<String, ChannelHandlerContext> channel = new HashMap<>(16);
public Map<String, ChannelHandlerContext> getChannel() {
return channel;
}
public void setChannel(String key, ChannelHandlerContext val) {
this.channel.put(key, val);
}
}
4、配置类NettyConfig
@Configuration
public class NettyConfig {
@Value("${nettyServer.ip}")
private String serverIp;
@Value("${nettyServer.port}")
private int serverPort;
@Bean
public NettyBean getNettyBean() {
return new NettyBean();
}
@Bean
public NettyServer getNettyClient() {
NettyServer nettyServer = new NettyServer();
nettyServer.start(new InetSocketAddress(serverIp, serverPort));
return nettyServer;
}
}
5、配置文件
server:
port: 10019
nettyServer:
ip: 127.0.0.1
port: 8888
nettyClient:
ip: 127.0.0.1
port: 8889
二、客户端接收
客户端与转发服务同理,与转发服务的区别为无需再次转发消息,而是直接处理。
NettyClient
public class NettyClient {
private static final Logger LOG = LoggerFactory.getLogger(NettyClient.class);
private final AtomicInteger threadNumber = new AtomicInteger(1);
ThreadPoolExecutor executor = new ThreadPoolExecutor(0, 10, 60,
TimeUnit.SECONDS, new SynchronousQueue<Runnable>()
, r -> new Thread(r,"NettyClient-Thread" + threadNumber.getAndIncrement()));
@Autowired
NettyClientHandler nettyClientHandler;
public void start(InetSocketAddress address) {
try {
executor.execute(() -> {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(nettyClientHandler);
LOG.info("--------------客户端upd服务启动----------------");
Channel channel = b.bind(address.getAddress(),address.getPort()).sync().channel();
channel.closeFuture().await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
NettyClientHandler
@Component
public class NettyClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
@Autowired
private NettyBean nettyBean;
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
System.out.println("客户端收到消息:" + msg.content().toString(StandardCharsets.UTF_8));
//保存连接上下文
nettyBean.setChannel(msg.sender().getHostName(), ctx);
}
}
三、测试
使用测试工具发送消息进行测试
转发服务收到消息并转发到客户端
客户端收到消息