美文网首页
SpringBoot2+Netty+WebSocket(nett

SpringBoot2+Netty+WebSocket(nett

作者: Java架构小喳喳 | 来源:发表于2019-06-24 14:51 被阅读0次

    关于Netty

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

    MAVEN依赖

    <dependencies>

    <!-- https://mvnrepository.com/artifact/io.netty/netty-all -->

    <dependency>

    <groupId>io.netty</groupId>

    <artifactId>netty-all</artifactId>

    <version>4.1.36.Final</version>

    </dependency>

    </dependencies>

    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<SocketChannel>() { // 绑定客户端连接时候触发操作

                            @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<TextWebSocketFrame>{

        @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,发送消息,以及消息反馈

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd">

    <html xmlns="http://www.w3.org/1999/xhtml">

    <head>

        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

        <title>Netty-Websocket</title>

        <script type="text/javascript">

            // by zhengkai.blog.csdn.net

            var socket;

            if(!window.WebSocket){

                window.WebSocket = window.MozWebSocket;

            }

            if(window.WebSocket){

                socket = new WebSocket("ws://127.0.0.1:12345/ws");

                socket.onmessage = function(event){

                    var ta = document.getElementById('responseText');

                    ta.value += event.data+"\r\n";

                };

                socket.onopen = function(event){

                    var ta = document.getElementById('responseText');

                    ta.value = "Netty-WebSocket服务器。。。。。。连接  \r\n";

                };

                socket.onclose = function(event){

                    var ta = document.getElementById('responseText');

                    ta.value = "Netty-WebSocket服务器。。。。。。关闭 \r\n";

                };

            }else{

                alert("您的浏览器不支持WebSocket协议!");

            }

            function send(message){

                if(!window.WebSocket){return;}

                if(socket.readyState == WebSocket.OPEN){

                    socket.send(message);

                }else{

                    alert("WebSocket 连接没有建立成功!");

                }

            }

        </script>

    </head>

    <body>

    <form onSubmit="return false;">

        <label>ID</label><input type="text" name="uid" value="${uid!!}" /> <br />

        <label>TEXT</label><input type="text" name="message" value="这里输入消息" /> <br />

        <br /> <input type="button" value="发送ws消息"

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

        <hr color="black" />

        <h3>服务端返回的应答消息</h3>

        <textarea id="responseText" style="width: 1024px;height: 300px;"></textarea>

    </form>

    </body>

    </html>

    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;

    }

    }

    效果演示


    思路优化

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

    相关文章

      网友评论

          本文标题:SpringBoot2+Netty+WebSocket(nett

          本文链接:https://www.haomeiwen.com/subject/wtfoqctx.html