SpringBoot整合Netty实现TCP通信

SpringBoot整合Netty,实现TCP通信

  1. 组成部分为:SpringBoot + Mybatis + netty;

  2. 开发环境为Java8 ,IDEA,Maven;

  3. 开始教程

    1. 使用 idea 创建 SpringBoot 项目;

    2. 创建完成后在 pom.xml 文件 dependencies 写入以下代码:

       <!--netty-->
              <dependency>
                  <groupId>io.netty</groupId>
                  <artifactId>netty-all</artifactId>
                  <version>4.1.17.Final</version>
              </dependency>
      
    3. 创建三个 Netty 所需类

      1. NettyServer 为服务器监听器

        package cn.han.han_parse.service;
        
        import io.netty.bootstrap.ServerBootstrap;
        import io.netty.channel.ChannelFuture;
        import io.netty.channel.ChannelOption;
        import io.netty.channel.EventLoopGroup;
        import io.netty.channel.nio.NioEventLoopGroup;
        import io.netty.channel.socket.nio.NioServerSocketChannel;
        import lombok.extern.slf4j.Slf4j;
        
        import java.net.InetSocketAddress;
        
        /**
         * @author hanyiming
         * @create 2021/9/9 10:08
         */
        @Slf4j
        public class NettyServer {
            public void start() {
                System.out.println("这是Netty");
                InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8080);
                //new 一个主线程组
                EventLoopGroup bossGroup = new NioEventLoopGroup(1);
                //new 一个工作线程组
                EventLoopGroup workGroup = new NioEventLoopGroup(200);
                ServerBootstrap bootstrap = new ServerBootstrap()
                        .group(bossGroup, workGroup)
                        .channel(NioServerSocketChannel.class)
                        .childHandler(new ServerChannelInitializer())
                        .localAddress(socketAddress)
                        //设置队列大小
                        .option(ChannelOption.SO_BACKLOG, 1024)
                        // 两小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文
                        .childOption(ChannelOption.SO_KEEPALIVE, true);
                //绑定端口,开始接收进来的连接
                try {
                    ChannelFuture future = bootstrap.bind(socketAddress).sync();
                    log.info("服务器启动开始监听端口: {}", socketAddress.getPort());
                    future.channel().closeFuture().sync();
                } catch (InterruptedException e) {
                    log.error("服务器开启失败", e);
                } finally {
                    //关闭主线程组
                    bossGroup.shutdownGracefully();
                    //关闭工作线程组
                    workGroup.shutdownGracefully();
                }
            }
        }
        
        
      2. NettyServerHandler 为处理器

        • 注意在此处如果没写Controller层,需要在本类中添加@Component 注解,并初始化所需要的service层和mapper层;如果不需要可以删除,在以下代码中有@Component 注解;
        package cn.han.han_parse.service;
        
        import cn.han.han_parse.dao.BasicMapper;
        import cn.han.han_parse.entity.Basic;
        import cn.han.han_parse.util.ParseMessage;
        import io.netty.channel.ChannelHandlerContext;
        import io.netty.channel.ChannelInboundHandlerAdapter;
        import lombok.extern.slf4j.Slf4j;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.stereotype.Component;
        
        import javax.annotation.PostConstruct;
        
        /**
         * @author hanyiming
         * @create 2021/9/9 10:12
         */
        @Slf4j
        @Component
        public class NettyServerHandler extends ChannelInboundHandlerAdapter {
        
            public static NettyServerHandler nettyServerHandler;
        
            @Autowired
            private BasicService basicService;
        
            @Autowired
            private BasicMapper basicMapper;
        
            @PostConstruct
            public void init() {
                nettyServerHandler = this;
                nettyServerHandler.basicService = this.basicService;
                nettyServerHandler.basicMapper = this.basicMapper;
                // 初使化时将已静态化的testService实例化
            }
        
            /**
             * 客户端连接会触发
             */
            @Override
            public void channelActive(ChannelHandlerContext ctx) throws Exception {
                log.info("连接成功...");
            }
        
            /**
             * 客户端发消息会触发
             */
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                log.info("服务器收到消息: {}", msg.toString());
                //此处为解析tcp参数所需要的方法!!!自定义
                /*final Basic parse = ParseMessage.parse(ctx, msg.toString());
                nettyServerHandler.basicService.addBasic(parse);*/
                ctx.write("你也好哦");
                ctx.flush();
            }
        
        
            /**
             * 发生异常触发
             */
            @Override
            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                cause.printStackTrace();
                ctx.close();
            }
        }
        
        
      3. ServerChannelInitializer 服务初始化器,

        package cn.han.han_parse.service;
        
        import cn.han.han_parse.util.MyDecode;
        import io.netty.channel.ChannelInitializer;
        import io.netty.channel.socket.SocketChannel;
        import io.netty.handler.codec.string.StringDecoder;
        import io.netty.handler.codec.string.StringEncoder;
        import io.netty.util.CharsetUtil;
        import lombok.extern.slf4j.Slf4j;
        
        /**
         * @author hanyiming
         * @create 2021/9/9 10:10
         */
        @Slf4j
        public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
        
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                //添加编解码,此处代码为解析tcp传过来的参数,为UTF-8格式,可以自定义解码格式
                socketChannel.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
                socketChannel.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
                socketChannel.pipeline().addLast(new NettyServerHandler());
            }
        }
        
        
      4. 此处为我所需的进制转换规则:

         /**
             * 十六进制转换为十进制
             *
             * @param content
             * @return
             */
            public static int covert(String content) {
                int number = 0;
                String[] HighLetter = {"A", "B", "C", "D", "E", "F"};
                Map<String, Integer> map = new HashMap<>();
                for (int i = 0; i <= 9; i++) {
                    map.put(i + "", i);
                }
                for (int j = 10; j < HighLetter.length + 10; j++) {
                    map.put(HighLetter[j - 10], j);
                }
                String[] str = new String[content.length()];
                for (int i = 0; i < str.length; i++) {
                    str[i] = content.substring(i, i + 1);
                }
                for (int i = 0; i < str.length; i++) {
                    number += map.get(str[i]) * Math.pow(16, str.length - 1 - i);
                }
                return number;
            }
        
            /**
             * 十进制转换为ASCII码
             *
             * @param ascii
             * @return
             */
            public static String dec2Str(String ascii) {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < ascii.length() - 1; i += 2) {
                    String h = ascii.substring(i, (i + 2));
                    // 这里第二个参数传10表10进制
                    int decimal = Integer.parseInt(h, 10);
                    sb.append((char) decimal);
                }
                return sb.toString();
            }
        
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值