Netty通过WebSocket编程实现服务器和客户端长连接

1、编写服务端

public class MyServer {
    public static void main(String[] args) {
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(boss, worker)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            //基于http协议,使用http的编码和解码器
                            pipeline.addLast(new HttpServerCodec());
                            //以块方式写,添加ChunkedWriteHandler处理器
                            pipeline.addLast(new ChunkedWriteHandler());
							/*
                    		  1. http数据在传输过程中是分段, HttpObjectAggregator ,就是可以将多个段聚合
                              2. 这就是为什么,当浏览器发送大量数据时,就会发出多次http请求
                     		*/
                            pipeline.addLast(new HttpObjectAggregator(8192));
                            /*
                             * ws://localhost:8888/hello 表示请求的uri
                             *  WebSocketServerProtocolHandler 核心功能是将http协议升级为ws协议,保持长连接
                             */
                            pipeline.addLast(new WebSocketServerProtocolHandler("/hello"));
                            //业务处理的handler
                            pipeline.addLast(new MyTextWebSocketFrameHandler());
                        }
                    });
            ChannelFuture channelFuture = bootstrap.bind(8888).sync();
            channelFuture.channel().closeFuture().sync();
        }catch (Exception e) {

        }finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}

2、编写业务处理handler

public class MyTextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        System.out.println("服务器端收到消息 " + msg.text());
        //发送到web客户端
        ctx.channel().writeAndFlush(new TextWebSocketFrame("服务器时间" + LocalDateTime.now() + ", " + msg.text() + "\n"));
    }

    /**
     * @Description web客户端连接后调用
     **/
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println("服务器 handlerAdded 被调用 " + ctx.channel().id().asLongText());
        System.out.println("服务器 handlerAdded 被调用 " + ctx.channel().id().asShortText());
    }


    @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 {
        ctx.close();
    }
}

3、编写web客户端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    var socket;
    if (window.WebSocket) {
        socket = new WebSocket("ws://localhost:8888/hello");
        //接受服务器的信息
        socket.onmessage = function (ev) {
            var rt = document.getElementById("responseText")
            rt.value = rt.value + ev.data;
        }
        //连接开启
        socket.onopen = function (ev) {
            var rt = document.getElementById("responseText");
            rt.value = "连接开启了...";
        }
        //连接关闭
        socket.onclose = function (ev) {
            var rt = document.getElementById("responseText");
            rt.value = rt.value + "\n" + "连接关闭了...";
        }
    }else {
        alert("当前浏览器不支持websocket")
    }
    function send(message) {
        if (!window.socket) {
            return;
        }
        if (socket.readyState == WebSocket.OPEN) {
            socket.send(message);
        }else {
            alert("连接未开启...")
        }
    }
</script>
<form action="/hello" method="get" onsubmit="return false">
    <textarea name="message" style="height: 300px; width: 300px;"></textarea>
    <input type="button" value="发送消息" onclick="send(this.form.message.value)"/>
    <textarea id="responseText" style="height: 300px; width: 300px;"></textarea>
    <input type="button" value="清空内容" onclick="document.getElementById('responseText').value = ''"/>
</form>
</body>
</html>

4、效果
在这里插入图片描述
当服务器关闭后,客户端检测到:
在这里插入图片描述
当客户端关闭后,服务端检测到:
在这里插入图片描述

发布了26 篇原创文章 · 获赞 0 · 访问量 548

猜你喜欢

转载自blog.csdn.net/qq_36609994/article/details/105092334