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>

測試結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM