SpringBoot2+Netty+WebSocket(netty实现websocket)

关于Netty

Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架。

MAVEN依赖

io.netty

netty-all

4.1.36.Final

SpringBootApplication

启动器中需要new一个NettyServer,并显式调用启动netty。

@SpringBootApplication

public class SpringCloudStudyDemoApplication {

public static void main(String[] args) {

SpringApplication.run(SpringCloudStudyDemoApplication.class,args);

try {

new NettyServer(12345).start();

System.out.println("https://blog.csdn.net/moshowgame");

System.out.println("http://127.0.0.1:6688/netty-websocket/index");

}catch(Exception e) {

System.out.println("NettyServerError:"+e.getMessage());

}}}

NettyServer

启动的NettyServer,这里进行配置

/**

* NettyServer Netty服务器配置

* @author zhengkai.blog.csdn.net

* @date 2019-06-12

*/

public class NettyServer {

    private final int port;

    public NettyServer(int port) {

        this.port = port;

    }

    public void start() throws Exception {

        EventLoopGroup bossGroup = new NioEventLoopGroup();

        EventLoopGroup group = new NioEventLoopGroup();

        try {

            ServerBootstrap sb = new ServerBootstrap();

            sb.option(ChannelOption.SO_BACKLOG, 1024);

            sb.group(group, bossGroup) // 绑定线程池

                    .channel(NioServerSocketChannel.class) // 指定使用的channel

                    .localAddress(this.port)// 绑定监听端口

                    .childHandler(new ChannelInitializer() { // 绑定客户端连接时候触发操作

                        @Override

                        protected void initChannel(SocketChannel ch) throws Exception {

                            System.out.println("收到新连接");

                            //websocket协议本身是基于http协议的,所以这边也要使用http解编码器

                            ch.pipeline().addLast(new HttpServerCodec());

                            //以块的方式来写的处理器

                            ch.pipeline().addLast(new ChunkedWriteHandler());

                            ch.pipeline().addLast(new HttpObjectAggregator(8192));

                            ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws", "WebSocket", true, 65536 * 10));

                            ch.pipeline().addLast(new MyWebSocketHandler());

                        }

                    });

            ChannelFuture cf = sb.bind().sync(); // 服务器异步创建绑定

            System.out.println(NettyServer.class + " 启动正在监听: " + cf.channel().localAddress());

            cf.channel().closeFuture().sync(); // 关闭服务器通道

        } finally {

            group.shutdownGracefully().sync(); // 释放线程池资源

            bossGroup.shutdownGracefully().sync();

        }

    }

}

MyChannelHandlerPool

通道组池,管理所有websocket连接

/**

* MyChannelHandlerPool

* 通道组池,管理所有websocket连接

* @author zhengkai.blog.csdn.net

* @date 2019-06-12

*/

public class MyChannelHandlerPool {

    public MyChannelHandlerPool(){}

    public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

}

MyWebSocketHandler

处理ws一下几种情况:

channelActive与客户端建立连接

channelInactive与客户端断开连接

channelRead0客户端发送消息处理

/**

* MyWebSocketHandler

* WebSocket处理器,处理websocket连接相关

* @author zhengkai.blog.csdn.net

* @date 2019-06-12

*/

public class MyWebSocketHandler extends SimpleChannelInboundHandler{

    @Override

    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        System.out.println("与客户端建立连接,通道开启!");

        //添加到channelGroup通道组

        MyChannelHandlerPool.channelGroup.add(ctx.channel());

    }

    @Override

    public void channelInactive(ChannelHandlerContext ctx) throws Exception {

        System.out.println("与客户端断开连接,通道关闭!");

        //添加到channelGroup 通道组

        MyChannelHandlerPool.channelGroup.remove(ctx.channel());

    }

@Override

protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {

System.out.println("客户端收到服务器数据:" + msg.text());

        sendAllMessage(msg.text());

}

private void sendAllMessage(String message){

        //收到信息后,群发给所有channel

        MyChannelHandlerPool.channelGroup.writeAndFlush( new TextWebSocketFrame(message));

    }

}

socket.html

主要是连接ws,发送消息,以及消息反馈

   

    Netty-Websocket

   

   

   

   

                  onClick="send(this.form.uid.value+':'+this.form.message.value)" />

   


   

服务端返回的应答消息

   

Controller

写好了html当然还需要一个controller来引导页面。

@RestController

public class IndexController {

@GetMapping("/index")

public ModelAndView  index(){

ModelAndView mav=new ModelAndView("socket");

mav.addObject("uid", RandomUtil.randomNumbers(6));

return mav;

}

}

效果演示

SpringBoot2+Netty+WebSocket(netty实现websocket)_第1张图片
SpringBoot2+Netty+WebSocket(netty实现websocket)_第2张图片
SpringBoot2+Netty+WebSocket(netty实现websocket)_第3张图片


思路优化

由于netty不能像默认的websocket一样设置一些PathVariable例如{uid}等参数(暂未发现可以,如果有发现欢迎补充),所以很多时候发送到后台的报文可以设置一些特殊的格式,例如上文的004401:大家好,可以分解为userid:text,当然userid也可以是加密的一些报文,甚至可以学习其他报文一样设置加密区,这取决于大家的业务需要.

你可能感兴趣的:(SpringBoot2+Netty+WebSocket(netty实现websocket))