• Springboot+Netty搭建基于UDP协议的客户端(四)


    使用Netty+SpringBoot方式可以快速地开发一套基于UDP协议的服务端程序,同样的也可以开发客户端,一般使用UDP都是使用原生的方式,发送消息后就不管不问,也就是不需要确定消息是否收到,这里使用Netty创建的客户端和服务端倒是能够类似http协议那样请求数据,得到返回数据,实际上得到的就是服务端原路返回的数据。


    1、这里也使用SpringBoot+Netty创建,pom.xml文件导入依赖包

    ​
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    		<java.version>1.8</java.version>
    	</properties>
    
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.1.6.RELEASE</version>
    		<relativePath /> <!-- lookup parent from repository -->
    	</parent>
    
    	<dependencies>
    
    		<!--web模块的启动器 -->
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</dependency>
    		<!-- netty依赖 springboot2.x自动导入版本 -->
    		<dependency>
    			<groupId>io.netty</groupId>
    			<artifactId>netty-all</artifactId>
    		</dependency>
    
    	</dependencies>

    2、Netty客户端的类,包含main方法,这里就没有使用SpringBoot方式的启动

    package boot.netty.udp.client;
    
    
    import java.net.InetSocketAddress;
    import boot.netty.udp.client.adapter.BootNettyUdpClientSimpleChannelInboundHandler;
    import io.netty.bootstrap.Bootstrap;
    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;
    import io.netty.util.CharsetUtil;
    
    public class BootNettyUdpClient {
    
    	public void bind(String address, int port, String data) {
    
    		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 BootNettyUdpClientSimpleChannelInboundHandler());
    
                Channel channel = clientBootstrap.bind(0).sync().channel();
                channel.writeAndFlush(new DatagramPacket(
                    Unpooled.copiedBuffer(data, CharsetUtil.UTF_8),
                    new InetSocketAddress(address,port))).sync();
    
                //  与BootNettyUdpClientSimpleChannelInboundHandler中的ctx.channel().id().toString()是一样的值
                System.out.println("channnel 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");
    
    		// 指定某个套接字地址和发送的内容可以发送消息
    		// 该方式也可以封装成一个udp的客户端的send类
    		new BootNettyUdpClient().bind("127.0.0.1",9999,"I am client");
    
    
    	}
    
    }

    3、服务端I/O数据读写处理类

    package boot.netty.udp.client.adapter;
    
    
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    import io.netty.channel.socket.DatagramPacket;
    import io.netty.util.CharsetUtil;
    
    public class BootNettyUdpClientSimpleChannelInboundHandler 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("msg---"+strdata);
                // 与BootNettyUdpClient中的channel.id().toString()是一样的值
                System.out.println(ctx.channel().id().toString());
                //	收到服务端原路返回的消息后,不需要再次向服务端发送消息, 可以在这里暴力关闭,也可以在 channelReadComplete(ChannelHandlerContext ctx)内
                //  ctx.close();
    		} catch (Exception e) {
    
    		}
    	}
    
    	/**
    	 * 	重写方法
    	 * 	结构:
    	 * 	1.public class BootNettyUdpClientSimpleChannelInboundHandler 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();
        }
    
    }

    4、我们可以启动一个服务端(SpringBoot搭建基于UDP协议的服务端)然后调用main方法,可以看到服务端可以收到消息,客户端也可以收到服务端原路返回的时间戳消息

    	public static void main(String[] args) {
    
    		//  向网段内的所有机器广播UDP消息,这个没试过是不是这个原理
    		// new BootNettyUdpClient().bind("255.255.255.255",9999,"I am client");
    
    		// 指定某个套接字地址和发送的内容可以发送消息
    		// 该方式也可以封装成一个udp的客户端的send类
    		new BootNettyUdpClient().bind("127.0.0.1",9999,"I am client");
    
    
    	}


  • 相关阅读:
    (一)linux 系统命令与文件
    python(1)- 初识python
    四、计算机硬件知识整理
    三、计算机硬件历史
    二、网络基础之网络协议
    jmeter while循环使用
    gitlab分支管理
    gitlab基本操作
    JAVA多种向influxDB中插入数据方式
    JAVA类变量和实例变量
  • 原文地址:https://www.cnblogs.com/haolb123/p/16386736.html
Copyright © 2020-2023  润新知