Netty之UDP协议实现数据接收

UDP协议的介绍:

我就不多说了,参考 百度百科

跟我个人理解,需要注意的是:

1、UDP的有效端口范围在0-65535之间,大约49151的端口都代表动态端口

2、UDP是一种无连接的,不可靠的传输层协议

 

接下来就是Netty实现UDP,

使用Netty的好处?

他简化网络应用的编程过程开发,例如UDP和TCP的socket服务开发,他功能比较强大,并且提供了编码好解码的能力,并且很多著名的框架都是底层采用Netty,比如Dubbo,服务提供者和消费者之间的通信。淘宝的消息中间件 RocketMQ 的消息生产者和消息消费者之间

  • 易用性好
  • 性能好
  • 健壮性好
  • 安全性好

大致结构:

1.所需的netty的jar

        <!--netty-all -->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.49.Final</version>
        </dependency>

2.ThreeUdpServer

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;

/**
 * 	 <B>说	明<B/>:UdpServer
 */
public class ThreeUdpServer {

    private final Bootstrap bootstrap;
    private final NioEventLoopGroup acceptGroup;
    private Channel channel;
    public void start(String host,int port) throws Exception{
        try {
            channel = bootstrap.bind(host, port).sync().channel();
            System.out.println("ThreeUdpServerHandler start success"+port);
            channel.closeFuture().await();
        } finally {
            acceptGroup.shutdownGracefully();
        }
    }

    public Channel getChannel(){
        return channel;
    }

    public static ThreeUdpServer getInstance(){
        return UdpServerHolder.INSTANCE;
    }

    private static final class UdpServerHolder{
        static final ThreeUdpServer INSTANCE = new ThreeUdpServer();
    }

    private ThreeUdpServer(){
        bootstrap = new Bootstrap();
        acceptGroup = new NioEventLoopGroup();
        bootstrap.group(acceptGroup)
                .channel(NioDatagramChannel.class)
                .option(ChannelOption.SO_BROADCAST, true)
                .handler(new ChannelInitializer<NioDatagramChannel>() {
                    @Override
                    protected void initChannel(NioDatagramChannel ch)
                            throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new ThreeUdpServerHandler());
                    }
                });
    }
}

3.ThreeUdpServerHandler

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import lombok.extern.slf4j.Slf4j;

/**
 * 	 <B>说	明<B/>:
 *
 */
@Slf4j
public class ThreeUdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket>{

//    @Override
//    public void channelActive(ChannelHandlerContext ctx) throws Exception {
//        //当channel就绪后。
//        Channel incoming = ctx.channel();
//        System.out.println("UDP-Client:" + incoming.remoteAddress() + "上线");
//    }


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg)
            throws Exception {
        // 接受client的消息
        log.info("开始接收来自client的数据");
        final ByteBuf buf = msg.content();
        int readableBytes = buf.readableBytes();
        byte[] content = new byte[readableBytes];
        buf.readBytes(content);
        String clientMessage = new String(content,"UTF-8");
        log.info("Read clientMessage is: "+clientMessage);
        if(clientMessage.contains("UdpServer")){
            ctx.writeAndFlush(new DatagramPacket(Unpooled.wrappedBuffer("helloClient".getBytes()),msg.sender())).sync();
        }
    }

    //捕获异常
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("UdpServerHandler exceptionCaught" + cause.getMessage());
        cause.printStackTrace();
        ctx.close();
    }

}

4.ThreeUdpServerTest

public class ThreeUdpServerTest {

    private static final String host = "192.168.1.184";

    private static final int port = 60000;

    public static void main(String[] args) {
        try {
            ThreeUdpServer.getInstance().start(host, port);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

5.ThreeUdpClient

import com.zxk.netty.udp.three.decode.ThreeUdpClientDecoder;
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 io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.apache.tomcat.jni.Local;

import java.nio.charset.Charset;

/**
 * 	 <B>说	明<B/>:LogPush UDP client
 */
public class ThreeUdpClient {

    private final Bootstrap bootstrap;
    public final NioEventLoopGroup workerGroup;
    public static Channel channel;
    private static final Charset ASCII = Charset.forName("ASCII");

    public void start(Integer localPort) throws Exception{
        try {
            channel = bootstrap.bind(localPort).sync().channel();
            channel.closeFuture().await(1000);
        } finally {
//        	workerGroup.shutdownGracefully();
        }
    }

    public Channel getChannel(){
        return channel;
    }

    public static ThreeUdpClient getInstance(){
        return logPushUdpClient.INSTANCE;
    }

    private static final class logPushUdpClient{
        static final ThreeUdpClient INSTANCE = new ThreeUdpClient();
    }

    private ThreeUdpClient(){
        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)throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new ThreeUdpClientDecoder(ASCII));
                        pipeline.addLast(new StringEncoder(ASCII));
                        pipeline.addLast(new ThreeUdpClientHandler());
                    }
                });
    }

}

6.ThreeUdpClientHandler

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.concurrent.GenericFutureListener;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.List;


/**
 * 	 <B>说	明<B/>:
 */
@Slf4j
public class ThreeUdpClientHandler extends SimpleChannelInboundHandler<Object>{


	private static Channel channel = ThreeUdpClient.getInstance().getChannel();

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //当channel就绪后。
        log.info("UDP client channel is ready!");
//       ctx.writeAndFlush("started");//阻塞直到发送完毕  这一块可以去掉的
//       NettyUdpClientHandler.sendMessage("你好UdpServer", new InetSocketAddress("127.0.0.1",8888));
//       sendMessageWithInetAddressList(message);
//       log.info("client send message is: 你好UdpServer");
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
        //log.info("msg length "+msg.toString().length());
        log.info("来自服务端的消息msg "+msg);
    }

    public String bytesToHexString(byte[] bArray) {
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2){
                sb.append(0);
            }
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }



        /**
         * 向服务器发送消息
         * @param msg 按规则拼接的消息串
         * @param inetSocketAddress 目标服务器地址
         */
    public static void sendMessage(final String msg,final InetSocketAddress inetSocketAddress){
        if(msg == null){
            throw new NullPointerException("msg is null");
        }
        // TODO 这一块的msg需要做处理 字符集转换和Bytebuf缓冲区
        senderInternal(datagramPacket(msg, inetSocketAddress));
    }

    /**
     * 发送数据包并监听结果
     * @param datagramPacket
     */
    public static void senderInternal(final DatagramPacket datagramPacket,List<Channel> channelList) {
        for (Channel channel : channelList) {
            if(channel != null){
                channel.writeAndFlush(datagramPacket).addListener(new GenericFutureListener<ChannelFuture>() {
                    @Override
                    public void operationComplete(ChannelFuture future)
                            throws Exception {
                        boolean success = future.isSuccess();
                        if(log.isInfoEnabled()){
                            log.info("Sender datagramPacket result : "+success);
                        }
                    }
                });
            }
        }
    }

    /**
     * 组装数据包
     * @param msg 消息串
     * @param inetSocketAddress 服务器地址
     * @return DatagramPacket
     */
    private static DatagramPacket datagramPacket(String msg, InetSocketAddress inetSocketAddress){
        ByteBuf dataBuf = Unpooled.copiedBuffer(msg,Charset.forName("UTF-8"));
        DatagramPacket datagramPacket = new DatagramPacket(dataBuf, inetSocketAddress);
        return datagramPacket;
    }

    /**
     * 发送数据包服务器无返回结果
     * @param datagramPacket
     */
    private static void senderInternal(final DatagramPacket datagramPacket) {
        log.info("ThreeUdpClient.channel"+ThreeUdpClient.channel);
        if(ThreeUdpClient.channel != null){
            ThreeUdpClient.channel.writeAndFlush(datagramPacket).addListener(new GenericFutureListener<ChannelFuture>() {
                @Override
                public void operationComplete(ChannelFuture future)
                        throws Exception {
                    boolean success = future.isSuccess();
                    if(log.isInfoEnabled()){
                        log.info("Sender datagramPacket result : "+success);
                    }
                }
            });
        }else{
            throw new NullPointerException("channel is null");
        }
    }

}

7.自定义解码器ThreeUdpClientDecoder

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.util.internal.ObjectUtil;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class ThreeUdpClientDecoder extends MessageToMessageDecoder<DatagramPacket> {

    private final Charset charset;

    public ThreeUdpClientDecoder() {
        this(Charset.defaultCharset());
    }


    public ThreeUdpClientDecoder(Charset charset) {
        this.charset = (Charset) ObjectUtil.checkNotNull(charset, "charset");
    }

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, DatagramPacket packet, List<Object> list) throws Exception {
        final ByteBuf buf = packet.content();
        int readableBytes = buf.readableBytes();
        byte[] content = new byte[readableBytes];
        buf.readBytes(content);
//        解决返回16(HEX)进制问题, 将16进制转换成16进制字符串样式
//        StringBuffer sb = new StringBuffer(content.length);
//        String sTemp;
//        for (int i = 0; i < content.length; i++) {
//            sTemp = Integer.toHexString(0xFF & content[i]);
//            if (sTemp.length() < 2){
//                sb.append(0);
//            }
//            sb.append(sTemp.toUpperCase());
//        }
        list.add(new String(content));
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        log.error("--------数据读异常----------: ");
        cause.printStackTrace();
        ctx.close();
    }
}

8.ThreeUdpClientTest

@Slf4j
public class ThreeUdpClientTest {
    //服务端IP
    private static final String server_host = "192.168.1.184";

    //服务端端口 (UDP有效端口范围在 0-65535之间)
    private static final int server_port = 60000;

    public static void main(String[] args) {
        try {
            //启动ud客户端并定点端口
            ThreeUdpClient.getInstance().start(1000);
            int i = 0;
            while( i < 10){
                ThreeUdpClientHandler.sendMessage(new String("Hello UdpServer!!!"), new InetSocketAddress(server_host,server_port));
                log.info(i+" client send message is: Hello UdpServer");
                i++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

 

结果;依次运行ThreeUdpServerTest 和 ThreeUdpClientTest,效果如下:

服务daunt收到客户端的数据:

客户端向服务端发送消息,并得到回应

 

至此,简单的UDP实现到此结束, 至于更深奥的,博主任在努力学习中......

  • 10
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是一个简单的示例代码,演示了如何在Spring Boot应用程序中集成Netty实现UDP通信: 首先,我们需要添加Netty和Spring Boot的依赖项。在pom.xml文件中添加以下依赖项: ```xml <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.25.Final</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` 接下来,我们创建一个UDP服务类,实现NettyChannelInboundHandlerAdapter接口,以处理接收到的UDP消息。我们将其命名为UdpServerHandler类。 ```java @Component public class UdpServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { DatagramPacket packet = (DatagramPacket) msg; ByteBuf buf = (ByteBuf) packet.copy().content(); byte[] req = new byte[buf.readableBytes()]; buf.readBytes(req); String message = new String(req, CharsetUtil.UTF_8); System.out.println("Received message: " + message); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } } ``` 然后,我们创建一个UDP服务器类,使用UdpServerHandler类处理接收到的UDP消息。 ```java @Component public class UdpServer { @Autowired private UdpServerHandler udpServerHandler; private EventLoopGroup group = new NioEventLoopGroup(); @PostConstruct public void start() { try { Bootstrap b = new Bootstrap(); b.group(group) .channel(NioDatagramChannel.class) .option(ChannelOption.SO_BROADCAST, true) .handler(udpServerHandler); b.bind(9999).sync().channel().closeFuture().await(); } catch (InterruptedException e) { e.printStackTrace(); } finally { group.shutdownGracefully(); } } } ``` 最后,我们需要在Spring Boot应用程序中启用UDP服务器,通过添加@EnableAutoConfiguration和@ComponentScan注解来实现。 ```java @SpringBootApplication @EnableAutoConfiguration @ComponentScan("com.example") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 这样,我们就可以通过UDP协议在Spring Boot应用程序中实现数据通信了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值