一 使用udp进行通信
1.1 描述
使用netty采用udp协议模拟客户端和服务端进行通信。
1.2 服务端代码
/**
* @ClassName: UdpServer
* @Description:
* TODO
* 1有一个boostrap服务者
* 2有两个干活的,也就是处理IO的,一个是boss用于监听端口,一个work干活的
* 3配置UDP管道,UDP管道主要使用的是NioDatagramChannel
* 4然后使用pipeline进行配置,可以实现编码和解码等功能,然后寻找到我们的执行的处理的Handler类
* 5配置我们的服务,例如选择是广播和单播,读和写缓存
* 6绑定端口,获取通道
* 7优雅的关闭服务器
*
* @Author: liujianfu
* @Date: 2022/07/09 19:03:58
* @Version: V1.0
**/
public class UdpServer {
//打印日志
public static final Logger log = Logger.getLogger(UdpServer.class);
//给管道抽象出接口,给Channel更多的能力和配置,例如Channel的状态,参数,IO操作
//使用ChannelPipeline实现自定义IO
public static Channel channel;
public static void run() throws Exception {
//启动服务
EventLoopGroup workerGroup = new NioEventLoopGroup();
//优化使用的线程
final EventExecutorGroup group = new DefaultEventExecutorGroup(16);
try {
Bootstrap b = new Bootstrap();//udp不能使用ServerBootstrap
b.group(workerGroup).channel(NioDatagramChannel.class)//设置UDP通道
//设置udp的管道工厂
.handler(new ChannelInitializer<NioDatagramChannel>(){
//NioDatagramChannel标志着是UDP格式的
@Override
protected void initChannel(NioDatagramChannel ch)
throws Exception {
// TODO Auto-generated method stub
//创建一个执行Handler的容器
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
//执行具体的处理器
pipeline.addLast(group,"handler",new UdpServerHandler());//消息处理器
}
})//初始化处理器
//true / false 多播模式(UDP适用),可以向多个主机发送消息
.option(ChannelOption.SO_BROADCAST, true)// 支持广播
.option(ChannelOption.SO_RCVBUF, 2048 * 1024)// 设置UDP读缓冲区为2M
.option(ChannelOption.SO_SNDBUF, 1024 * 1024);// 设置UDP写缓冲区为1M
// 绑定端口,开始接收进来的连接 ,绑定的端口9999
ChannelFuture f = b.bind(Constants.PORT).sync();
//获取channel通道
channel=f.channel();
System.out.println("UDP Server 启动!");
// 等待服务器 socket 关闭 。
// 这不会发生,可以优雅地关闭服务器。
f.channel().closeFuture().sync();
}finally {
// 优雅退出 释放线程池资源
group.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
UdpServer.run();
}
}
2.服务端handler
/**
* @ClassName: UdpServerHandler
* @Description: TODO
* @Author: liujianfu
* @Date: 2022/07/09 19:08:44
* @Version: V1.0
**/
public class UdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
//打印日志
public static final Logger log = Logger.getLogger(UdpServerHandler.class);
//在事件循环中执行
private EventExecutor executor ;
//客户端与服务器端连接成功的时候触发
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
log.info("UDP通道已经连接");
System.out.println("UDP通道已经连接");
super.channelActive(ctx);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet)
throws Exception
{
// 读取收到的数据
ByteBuf buf = (ByteBuf) packet.copy().content();
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req, CharsetUtil.UTF_8);
System.out.println("【NOTE】>>>>>> 收到客户端的数据:"+body);
// 回复一条信息给客户端
/**
ctx.writeAndFlush(new DatagramPacket(
Unpooled.copiedBuffer("Hello,我是Server,我的时间戳是"+System.currentTimeMillis()
, CharsetUtil.UTF_8)
, packet.sender())).sync(); **/ //(Netty权威指南和Netty实战中都有谈到,不要在ChannelHandler方法中调用sync()或await()方法,会有可能引起死锁。)
//https://blog.youkuaiyun.com/weixin_39734304/article/details/118975742
ctx.writeAndFlush(new DatagramPacket(
Unpooled.copiedBuffer("Hello,我是Server,我的时间戳是"+System.currentTimeMillis()
, CharsetUtil.UTF_8)
, packet.sender())).sync();
}
//消息没有结束的时候触发
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
//捕获异常
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {
//logger.log(Level.INFO, "AuthServerInitHandler exceptionCaught");
log.error("UdpServerHandler exceptionCaught"+cause.getMessage());
System.out.println("UdpServerHandler exceptionCaught"+cause.getMessage());
cause.printStackTrace();
//ctx.close();
}
}
1.3 客户端代码
/**
* @ClassName: UdpClient
* @Description: TODO
* @Author: liujianfu
* @Date: 2022/07/09 19:11:36
* @Version: V1.0
**/
public class UdpClient {
public static void run(int port) {
//创建于服务端就是连接操作,创建线程
EventLoopGroup group = new NioEventLoopGroup();
try {
//开始客户端的服务,和管道的设置
Bootstrap b = new Bootstrap();
b.group(group).channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST,true)
.option(ChannelOption.SO_RCVBUF, 2048 * 1024)// 设置UDP读缓冲区为2M
.option(ChannelOption.SO_SNDBUF, 1024 * 1024)// 设置UDP写缓冲区为1M
.handler(new UdpClientHandler());
//服务端绑定的管道的端口
Channel ch = b.bind(8888).sync().channel();
// 向网段类所有机器广播发UDP,这是想客户端发送内容
ch.writeAndFlush(new DatagramPacket(
Unpooled.copiedBuffer("我是在客户端写的!!!", CharsetUtil.UTF_8),
//地址
new InetSocketAddress(
"localhost",port
))).sync();
//如果超过长时间则表示超时
if(!ch.closeFuture().await(15000)){
System.out.println("查询超时!!!");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//优雅的关闭释放内存
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception{
int port = 666;
int k=100;
for(int m=0;m<10;m++){
Thread.sleep(2000);
new UdpClient().run(port);
}
}
}
2.客户端hadler
/**
* @ClassName: UdpClientHandler
* @Description: TODO
* @Author: liujianfu
* @Date: 2022/07/09 19:17:33
* @Version: V1.0
**/
public class UdpClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
//接受服务端发送的内容
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
String body = msg.content().toString(CharsetUtil.UTF_8);
System.out.println(body+"这是服务端发送的内容");
//这里接收到服务端发送的1内容
}
//捕获异常
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
ctx.close();
}
}
1.4 调式运行
1.客户端

2.服务端
Netty实现UDP通信详解
382

被折叠的 条评论
为什么被折叠?



