• Netty学习——通过websocket编程实现基于长连接的双攻的通信


    Netty学习(一)基于长连接的双攻的通信,通过websocket编程实现


     效果图,客户端和服务器端建立起长连接,客户端发送请求,服务器端响应

     但是目前缺少心跳,如果两个建立起来的连接,一个断网之后,另外一个是感知不到对方已经断掉的。以后使用心跳技术来进行连接检测

    须知:

    状态码101,代表 协议转换,从HTTP协议升级为WebSocket协议

    HTTP协议,一般访问的时候:是 Http://localhost:8080/ws

    WebSocket协议,访问的时候,需要是:ws://localhost:8080/ws


     实现代码:

    服务器端:

    package com.dawa.netty.fifthexample;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.handler.logging.LogLevel;
    import io.netty.handler.logging.LoggingHandler;
    
    import java.net.InetSocketAddress;
    
    /**
     * @Title: MyServer
     * @Author: 大娃
     * @Date: 2019/11/28 14:02
     * @Description:
     */
    public class MyServer {
        public static void main(String[] args)  throws Exception{
            //定义一个线程组 , 事件循环组 。 异步的NIO , 就是一个死循环。
            EventLoopGroup bossGroutp = new NioEventLoopGroup();  //不断的接受连接,但是不处理
            EventLoopGroup workerGroup = new NioEventLoopGroup(); // 完成后续处理,把结果返回给客户端
            try {
    
                //服务端,启动类
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                //group方法,有两个参数的,有一个参数的
                serverBootstrap.group(bossGroutp, workerGroup).channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO))
                        .childHandler(new WebSocketChannelInitializer()); //字处理器,自己 定义的
    
                ChannelFuture channelFuture = serverBootstrap.bind(new InetSocketAddress(8899)).sync();
                channelFuture.channel().closeFuture().sync();
            } finally {
                //优雅关闭、
                bossGroutp.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    }
    package com.dawa.netty.fifthexample;
    
    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;
    
    /**
     * @Title: WebSocketChannelInitializer
     * @Author: 大娃
     * @Date: 2019/11/28 14:06
     * @Description:
     */
    public class WebSocketChannelInitializer extends ChannelInitializer<SocketChannel> {
    
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
            pipeline.addLast(new HttpServerCodec());
            pipeline.addLast(new ChunkedWriteHandler());//新的处理器   块
            pipeline.addLast(new HttpObjectAggregator(8192)); //将分开的段,给聚合到一起,形成完整的HTTP响应。很重要的一个对象,在处理HTTP的时候
            pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
            pipeline.addLast(new TextWebSocketFrameHandler());
        }
    }
    package com.dawa.netty.fifthexample;
    
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
    
    import java.time.LocalDateTime;
    
    /**
     * @Title: TextWebSocketFrameHandler
     * @Author: 大娃
     * @Date: 2019/12/2 08:33
     * @Description:
     */
    public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    
        /**
         *
         * @param ctx 上下文对象
         * @param msg //文本帧对象
         * @throws Exception 抛异常
         */
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
            System.out.println("收到消息:"+msg.text());
            ctx.channel().writeAndFlush(new TextWebSocketFrame("服务器时间:"+ LocalDateTime.now() )); //不能直接传入 字符串.因为不同协议的规范不同,websocket要求要传回这种的对象
        }
    
        @Override
        public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
            System.out.println("handlerAdded:" + ctx.channel().id().asLongText());//每一个channel 都有一个唯一的id值与其对应
        }
    
        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
            System.out.println("HandlerRemoved:" + ctx.channel().id().asLongText());
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            ctx.channel().close();
        }
    }

    客户端(使用HTML,JS来代替模拟客户端)

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>websocket客户端</title>
     6 </head>
     7 <body>
     8 <!--
     9 
    10 -->
    11 <script type="text/javascript">
    12     //使用浏览器,进行websocket服务器端的访问
    13     var socket;
    14     if (window.WebSocket) {//判断浏览器是否支持websocket
    15         socket = new WebSocket("ws:localhost:8899/ws"); //建立websocket连接
    16         socket.onmessage = function (ev) { //如果socket收到消息,这个onmessage方法就会被回调
    17             var ta = document.getElementById('responseText');
    18             ta.value = ta.value + "
    " + ev.data;
    19         };
    20 
    21         socket.onopen=function (ev) {//当连接被打开的时候,执行的回调
    22             var ta = document.getElementById('responseText');
    23             ta.value = "连接开启!";
    24         };
    25 
    26         socket.onclose = function (ev) {
    27             var ta = document.getElementById('responseText');
    28             ta.value = ta.value + "
    " + "连接断开!";
    29         };
    30     } else {
    31         alert("浏览器不支持Websocket")
    32     }
    33 
    34     function send(message) {
    35         if (!window.WebSocket) {
    36             return;
    37         }
    38         if (socket.readyState === WebSocket.OPEN) {
    39             socket.send(message);
    40         } else {
    41             alert("连接未开启");
    42         }
    43     }
    44 </script>
    45 
    46 <!--客户端访问后台 websocket程序-->
    47 <form action="" onsubmit="return false;">
    48     <textarea name="message" style=" 400px;height: 200px;"></textarea>
    49 
    50     <input type="button" value="发送数据" onclick="send(this.form.message.value)">
    51 
    52     <h3>服务器端输出:</h3>
    53     <textarea id="responseText" style=" 400px;height: 300px;"></textarea>
    54     <input type="button" onclick="javascript:document.getElementById('responseText').value='';" value="清空内容">
    55 </form>
    56 </body>
    57 </html>
  • 相关阅读:
    winform窗体扁平化设置,窗体移动,关闭
    WPF按钮控件模板
    C#连接Sqlite报错:{"试图加载格式不正确的程序。 (异常来自 HRESULT:0x8007000B)"}
    C#SQLite使用教程笔记
    C#自定义控件导航菜单(自定义事件,属性)
    LCS局域网屏幕监控系统安装指导
    System.Data.SQLite.dll 未安装或者版本冲突,按下面步骤操作即可 1、从Nuget卸载所有项目的System.Data.SQLite.dll 和SqlSugar,检查引用中是否还存在,存在直接删掉引用,然后Nuget重新安装即可
    C#项目脱落NuGet
    JavaScript跨域总结与解决办法
    回流与重绘:CSS性能让JavaScript变慢?
  • 原文地址:https://www.cnblogs.com/bigbaby/p/11969625.html
Copyright © 2020-2023  润新知