SpringBoot集成Netty实现简单通信

演示效果:

SpringBoot集成Netty实现简单通信_第1张图片SpringBoot集成Netty实现简单通信_第2张图片

一:Netty简介

Netty 是一个基于NIO的客户、服务器端的编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发。

Netty 是一个吸收了多种协议(包括FTP、SMTP、HTTP等各种二进制文本协议)的实现经验,并经过相当精心设计的项目。

这是官方的一个阐述,简而言之来说就是一套高性能 支持高并发场景下的通信中间件。

 

二:SpringBoot集成Netty

1: 新建项目 引入相关依赖

SpringBoot集成Netty实现简单通信_第3张图片

  
            org.springframework.boot
            spring-boot-starter
        

        
            org.springframework.boot
            spring-boot-starter-web
        

        
        
            io.netty
            netty-all
            4.1.25.Final
        

2:新建Netty服务端实例 (WebSocketNettyServer)

package com.cposnettyim.cposim.im;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * @auth Lxl
 * @since 2021/1/30
 */
public class WebSocketNettyServer {

    public static void main(String[] args) {
           //创建两个线程
           NioEventLoopGroup mainGrp = new NioEventLoopGroup(); //主线程池
           NioEventLoopGroup subGrp = new NioEventLoopGroup(); //从线程池

          try {
              //创建Netty服务器启动对象
              ServerBootstrap bootstrap = new ServerBootstrap();

              //创建服务器启动对象
              bootstrap
                      //指定上述定义的主从线程
                      .group(mainGrp, subGrp)
                      //指定Netty通道类型
                      .channel(NioServerSocketChannel.class)
                      //指定通道初始化器用来加载当Channel收到消息事件后 如何进行业务处理
                      .childHandler(new WebsocketChannelInitializer());
              //绑定服务器端口
              ChannelFuture future = bootstrap.bind(9066);
              //等待服务器关闭
              future.channel().closeFuture().sync();
          }catch (Exception e){
               e.printStackTrace();
          }finally {
              //关闭服务器
              mainGrp.shutdownGracefully();
              subGrp.shutdownGracefully();
          }

    }
}

3:新增Netty通道初始化器

package com.cposnettyim.cposim.im;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

/**
 * @auth Lxl
 * @since 2021/1/30
 *
 *  通道初始化器
 */
public class WebsocketChannelInitializer extends ChannelInitializer {


    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {

        //获取管道
        ChannelPipeline pipeline = socketChannel.pipeline();

        //设置http编解码器
        pipeline.addLast(new HttpServerCodec());
        //设置用于支持大数据流的支持
        pipeline.addLast(new ChunkedWriteHandler());
        //设置聚合器合器主要讲HttpMessage聚合成FullHttpRequest/Response
        pipeline.addLast(new HttpObjectAggregator(1024*64));


        //指定接手对应的路由信息
        //必须使用ws后缀结尾的url才接收处理
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));

        //设置自定义的Handler
        pipeline.addLast(new MyChatHandler());


    }

}

4:自定义Handlder处理数据

package com.cposnettyim.cposim.im;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @auth Lxl
 * @since 2021/1/30
 *   自定义Handlder
 */
public class MyChatHandler extends SimpleChannelInboundHandler {

    //用来保存所有客户端连接
    private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    private SimpleDateFormat sdf =new SimpleDateFormat("YYYY-MM-dd HH:mm");

    //当通道(channel)内有新的消息会自动调用
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
         //获取客户端发送过来的文本消息
        String text = msg.text();
        System.out.println("接收到的消息:"+text);

       for(Channel channel : clients){
           String asLongText = channel.id().asLongText().substring(0,6);
           channel.writeAndFlush(new TextWebSocketFrame(asLongText+"&"+sdf.format(new Date())+"&"+text));
       }
    }

    //当有新的客户端连接服务器后 会自动调用这个方法
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        clients.add(ctx.channel());
    }
}

5: 启动 测试!

1:web聊天界面默认地址:http://127.0.0.1:20999/Mychat.html

2:Netty服务地址:ws://127.0.0.1:9066/ws  (前台调试)





    
    CposIM在线聊天




6:外网访问(配置内网穿透 修改地址)

为什么要提到外网访问呢? 因为这个地方容易踩坑,很多时候本地局域网测试了 然后拿到手机上一试发现点击的发送消息并没反应 其实就是本地地址需要配置成传统地址才能访问

推荐两块免费的内网穿透工具 超级好用! Natapp 和  Sunny-Ngrok 操作很便捷 可以将内网直接映射成外网访问 这样手机也能实时在线聊天了

穿透两个地址: 一个是Socket的服务地址  另外一个就是web页面访问地址了 记得穿透完以后改地址

你可能感兴趣的:(框架)