netty结合websocket使用

首先需要在后台建立netty服务器启动类;

package com.cxy;

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;

/***
 * @ClassName: WsNetty
 * @Description:
 * @Auther: cxy
 * @Date: 2019/2/5:14:15
 * @version : V1.0
 */
public class WsNetty {
    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 WSServerInitialzer());//添加助手类 ChannelFuture channelFuture= serverBootstrap.bind(8088).sync(); channelFuture.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); }finally { mainGroup.shutdownGracefully(); subGroup.shutdownGracefully();//优雅的关闭主从线程池 } } }

第二创建初始化类;

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;

public class WSServerInitialzer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        
        // websocket 基于http协议,所以要有http编解码器
        pipeline.addLast(new HttpServerCodec());
        // 对写大数据流的支持 
        pipeline.addLast(new ChunkedWriteHandler());
        // 对httpMessage进行聚合,聚合成FullHttpRequest或FullHttpResponse
        // 几乎在netty中的编程,都会使用到此hanler
        pipeline.addLast(new HttpObjectAggregator(1024*64));
        
        // ====================== 以上是用于支持http协议    ======================
        
        // ====================== 以下是支持httpWebsocket ======================
        
        /**
         * websocket 服务器处理的协议,用于指定给客户端连接访问的路由 : /ws
         * 本handler会帮你处理一些繁重的复杂的事
         * 会帮你处理握手动作: handshaking(close, ping, pong) ping + pong = 心跳
         * 对于websocket来讲,都是以frames进行传输的,不同的数据类型对应的frames也不同
         */
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
        
        // 自定义的handler
        pipeline.addLast(new ChatHandler());
    }

}

第三步:创建助手类

import java.time.LocalDateTime;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;

/**
 * 
 * @Description: 处理消息的handler
 * TextWebSocketFrame: 在netty中,是用于为websocket专门处理文本的对象,frame是消息的载体
 */
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    // 用于记录和管理所有客户端的channle
    private static ChannelGroup clients = 
            new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) 
            throws Exception {
        // 获取客户端传输过来的消息
        String content = msg.text();
        System.out.println("接受到的数据:" + content);
        
//        for (Channel channel: clients) {
//            channel.writeAndFlush(
//                new TextWebSocketFrame(
//                        "[服务器在]" + LocalDateTime.now() 
//                        + "接受到消息, 消息为:" + content));
//        }
        // 下面这个方法,和上面的for循环,一致
        clients.writeAndFlush(
                new TextWebSocketFrame(
                        "[服务器在]" + LocalDateTime.now() 
                        + "接受到消息, 消息为:" + content));
        
    }

    /**
     * 当客户端连接服务端之后(打开连接)
     * 获取客户端的channle,并且放到ChannelGroup中去进行管理
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        clients.add(ctx.channel());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        // 当触发handlerRemoved,ChannelGroup会自动移除对应客户端的channel
//        clients.remove(ctx.channel());
        System.out.println("客户端断开,channle对应的长id为:" 
                            + ctx.channel().id().asLongText());
        System.out.println("客户端断开,channle对应的短id为:" 
                            + ctx.channel().id().asShortText());
    }

    
    
}

前端页面:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <div>发送消息</div>
        <input type="text" id="msgContent" />
        <input type="button" value="点我发送" onclick="chat.chat1()" />
        <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://127.0.0.1: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+"<br/>"+e.data;
                            
                        }
                        
                    }else{
                        alert("浏览器不支持协议");
                    }
                    
                },
                chat1:function(){
                    var msg =document.getElementById("msgContent");
                    chat.socket.send(msg.value);
                    
                }
                
            };
            chat.init();
        </script>
    </body>
</html>

测试结果:

 

posted @ 2019-02-05 16:37  菩提树下的丁春秋  阅读(4811)  评论(1编辑  收藏  举报