码迷,mamicode.com
首页 > Web开发 > 详细

基于Netty的WebSocket长连接开发demo

时间:2021-03-08 14:19:50      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:状态码   mit   一个   init   trace   stream   支持   服务器   pip   

服务器端

启动类

package me.jar.netty.websocket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
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.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

/**
 * @Description
 * @Date 2021/3/7-10:31
 */
public class WebSocketServer {
    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            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));
                            /*
                            1.对于WebSocket,它的数据是以 帧(frame)形式传递
                            2.可以看到WebSocketFrame下面有六个子类
                            3.浏览器请求是 ws://localhost:8899/hello 表示请求的uri
                            4.WebSocketServerProtocolHandler 核心功能是将http协议升级为ws协议,保持长连接
                            5.是通过一个状态码 101
                             */
                            pipeline.addLast(new WebSocketServerProtocolHandler("/hello"));
                            // 自定义的Handler,处理业务逻辑
                            pipeline.addLast(new MyTextWebSocketFrameHandler());
                        }
                    });

            ChannelFuture cf = serverBootstrap.bind(8899).sync();
            System.out.println("服务器启动了。。。");
            cf.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

自定义处理器类

package me.jar.netty.websocket;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

import java.time.LocalDateTime;

/**
 * @Description 这里的TextWebSocketFrame类型,表示一个文本帧(Frame)
 * @Date 2021/3/7-10:49
 */
public class MyTextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
        System.out.println("服务器收到的消息->" + msg.text());
        // 回复消息
        ctx.writeAndFlush(new TextWebSocketFrame("服务器时间:" + LocalDateTime.now() + " >>> " + msg.text()));
    }

    // 当客户端连接后,触发方法
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        // id表示唯一的值,LongText是唯一的,ShortText不是唯一的
        System.out.println("HandlerAdded 被调用->" + ctx.channel().id().asLongText());
        System.out.println("HandlerAdded 被调用->" + ctx.channel().id().asShortText());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        System.out.println("handlerRemoved被调用->" + ctx.channel().id().asLongText());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        System.out.println("连接异常->" + cause.getMessage());
        ctx.close();
    }
}

 

客户端 html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket</title>
</head>
<body>
    <script>
        var websocket;
        if (window.WebSocket) {
            websocket = new WebSocket("ws://localhost:8899/hello");
            // 相当于channelRead0,ev,收到服务端回送的消息
            websocket.onmessage = function (ev) {
                var rt = document.getElementById("responseText");
                rt.value = rt.value + "\n" + ev.data;
            }
            // 相当于连接开启(感知到连接开启)
            websocket.onopen = function (ev) {
                var rt = document.getElementById("responseText");
                rt.value = "连接开启了。。。";
            }
            // 相当于连接关闭(感知到连接关闭)
            websocket.onclose = function (ev) {
                var rt = document.getElementById("responseText");
                rt.value = rt.value + "\n" + "连接关闭了。。。";
            }

            // 发送消息到服务器
            function send(message) {
                if (!websocket) { // 先判断socket是否创建好
                    return;
                }
                if (websocket.readyState = WebSocket.OPEN) {
                    // 通过socket发送消息
                    websocket.send(message);
                } else {
                    alert("连接没有开启");
                }
            }
        } else {
            alert("当前浏览器不支持webSocket");
        }
    </script>
    <form 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>

 

基于Netty的WebSocket长连接开发demo

标签:状态码   mit   一个   init   trace   stream   支持   服务器   pip   

原文地址:https://www.cnblogs.com/hello4world/p/14496347.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!