netty集成websocket

服务器

定义主从线程组、启动类、处理函数初始化器,设置通道方式,绑定服务器端口(具体可看博主上一篇HelloNetty服务器)

public class WSServer {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup mainGroup = new NioEventLoopGroup();
        EventLoopGroup subGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(mainGroup, subGroup)
                           .channel(NioServerSocketChannel.class)
                           .childHandler(new WSServerInitializer());
            ChannelFuture channelFuture = serverBootstrap.bind(8088).sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            mainGroup.shutdownGracefully();
            subGroup.shutdownGracefully();
        }
    }
}

定义初始化器WSServerInitializer,重写initChannel方法,从SocketChannel 中获取对应管道,添加相应处理器。websocket建立连接时基于Http协议,因此需要添加相应的http编解码器。添加netty支持的websocket协议处理器WebSocketServerProtocolHandler,最后添加自定义处理器

public class WSServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        // websocket基于Http协议,需要相应的编解码器
        pipeline.addLast(new HttpServerCodec());
        // 对写大数据流的支持
        pipeline.addLast(new ChunkedWriteHandler());
        // 对HttpMessage进行聚合,聚合成FullHttpRequest和FullHttpResponse
        // 因为netty中都需要,故都会聚合此handler
        pipeline.addLast(new HttpObjectAggregator(1024 * 64));
        // ================以上都是用于支持http协议==================
         /**
           * websocket服务器处理的协议,用于指定客户端第一次连接的路由
           * 会处理握手等动作
           * 对websocket,都是以frames传输,不同类型数据对应frames不同
           */
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
        // 自定义handler
        pipeline.addLast(new ChatHandler());
    }
}

自定义处理器处理websocket请求,TextWebSocketFrame是websocket的文本消息载体,DefaultChannelGroup(GlobalEventExecutor.INSTANCE)用于记录和管理客户端所有的channel,TextWebSocketFrame 为客户端传输过来的内容,同理,发送时也需要相同TextWebSocketFrame 载体。

/**
 * @description 处理websocket的handler
 * TextWebSocketFrame: 在netty,是用于为websocket专门处理文本的对象,frame是消息的载体
 */
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    // 用于记录和管理客户端所有的channel
    private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext,
                                TextWebSocketFrame msg) throws Exception {
        // 获取客户端传输过来的消息
        String content = msg.text();
        System.out.println("接收到的数据" + content);
        for (Channel client : clients) {
            client.writeAndFlush(new TextWebSocketFrame(
                    "[服务器在]" + LocalDateTime.now() + "接收到的消息是:" + content));
        }
    }
    // 当客户端连接服务器后,获取服务器channel,并且放到ChannelGroup中进行管理
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        clients.add(ctx.channel());
    }
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        // 当触发handlerRemoved,ChannelGroup会自动移除对应客户端channel
        System.out.println("客户端断开,channel对应的长id为" + ctx.channel().id().asLongText());
        System.out.println("客户端断开,channel对应的短id为" + ctx.channel().id().asShortText());
    }
}

handlerAdded和handlerRemovedchannel的生命周期函数,用于在channel的各个阶段对channel进行相应处理,handlerAdded为channel创建时执行,文中调用该钩子将channel放到ChannelGroup中进行管理,handlerRemoved为channel关闭时执行,同理,还有(未标记)exceptionCaught为channel异常时执行,channelActive,channelInactive,channelRead等钩子。

// 当客户端连接服务器后,获取服务器channel,并且放到ChannelGroup中进行管理
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        clients.add(ctx.channel());
    }
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        // 当触发handlerRemoved,ChannelGroup会自动移除对应客户端channel
        System.out.println("客户端断开,channel对应的长id为" + ctx.channel().id().asLongText());
        System.out.println("客户端断开,channel对应的短id为" + ctx.channel().id().asShortText());
    }

客户端

直接新建html脚本,创建websocket连接。
websocket连接步骤:

  1. 初始化socket
  2. 创建websocket对象,html5之后,一般浏览器都支持websocket,可直接new创建,new WebSocket(“ws://192.168.1.102:8088/ws”),ip与路径和服务器对应
  3. 处理websocket的生命周期函数,onopen ,onclose ,onmessage ,onerror
  4. 自定义处理器,调用socket.send发送消息

<html>
    <head>
        <meta charset="UTF-8">
        <title>title>
    head>
    <body>
        <div>发送消息:div>
        <input type="text" id="msgContent">
        <input type="button" value="发送" onclick="CHAT.chat()">
        <div>接受消息:div>
        <div id="receiveMsg" style="background-color:gainsboro;">div>
        <script type="application/javascript">
            window.CHAT = {
                socket: null,
                init: function() {
                    if (window.WebSocket) {
                        CHAT.socket = new WebSocket("ws://192.168.1.102:8088/ws");
                        CHAT.socket.onopen = function() {
                            console.log("连接建立成功~~")
                        };
                        CHAT.socket.onclose = function() {
                            console.log("连接关闭~~")
                        };
                        CHAT.socket.onerror = function() {
                            console.log("连接出错~~")
                        };
                        CHAT.socket.onmessage = function(e) {
                            console.log("接收到消息:" + e.data);
                            var receiveMsg = document.getElementById("receiveMsg");
                            var html = receiveMsg.innerHTML;
                            receiveMsg.innerHTML = html + "
"
+ e.data; }; } else { alert("该服务器不支持websocket协议") } }, chat: function() { var msg = document.getElementById("msgContent"); CHAT.socket.send(msg.value); } }; CHAT.init();
script> body> html>

你可能感兴趣的:(netty,websockt,html5)