WebSocket + Vue 的一個簡單示例

1. 提前瞭解

Netty 的簡單實例
https://blog.csdn.net/YKenan/article/details/106362104

2. 主方法類

package com.springCloud.netty.WebSocket;

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;

public class WebSocketServer {

    public static void main(String[] args) {
        // 創建主從線程
        EventLoopGroup mainGroup = new NioEventLoopGroup();
        EventLoopGroup subGroup = new NioEventLoopGroup();
        try {
            // 創建服務器
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(mainGroup, subGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new WebSocketServerInitializer());
            ChannelFuture sync = serverBootstrap.bind(8009).sync();
            sync.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            mainGroup.shutdownGracefully();
            subGroup.shutdownGracefully();
        }


    }
}

3. 通道初始化器

package com.springCloud.netty.WebSocket;

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 WebSocketServerInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        // 獲取管道 (pipeline)
        ChannelPipeline pipeline = socketChannel.pipeline();
        // Websocket 基於 http 協議, 所需要的 http 編碼器
        pipeline.addLast(new HttpServerCodec());
        // 在 http 上有一些數據流產生, 有大有小, 我們對其處理, 既然如此, 我們需要使用 netty 對下數據流讀寫提供支持, 這兩個類叫:
        pipeline.addLast(new ChunkedWriteHandler());
        // 對 httpMessage 進行聚合處理, 聚合成 request和 response
        pipeline.addLast(new HttpObjectAggregator(1024 * 64));
        // 本 handler 會幫你處理一些繁重複雜的事請, 會幫你處理握手動作: handshaking (close, ping, pong) ping + pong = 心跳, 對於 websocket 來講, 都是以 frame 進行傳輸的, 不同的數據類型對應的 frame 也不同.
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
        // 自定義的 handler
        pipeline.addLast(new ChatHandler());
    }

}

4. 消息處理器

package com.springCloud.netty.WebSocket;

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;

import java.time.LocalDateTime;

/**
 * 用於處理消息的 handler
 * 由於它的傳輸數據的載體時 frame, 這個 frame 在 netty 中, 是用於 websocket 專門處理文本對象的, frame 是消息的載體, 此類叫做: TextWebSocketFrame
 */
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    // 用於記錄和管理所有客戶端的 Channel
    private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
        // 獲取客戶端所傳輸的信息
        String text = textWebSocketFrame.text();
        System.out.println("接收到的數據: " + text);

        // 將數據刷新到客戶端上
        clients.writeAndFlush(
                new TextWebSocketFrame(
                        "[服務器在: "
                                + LocalDateTime.now()
                                + "接收到消息, 消息內容爲: "
                                + text
                                + "]"
                )
        );

    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        super.handlerAdded(ctx);
        clients.add(ctx.channel());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        super.handlerRemoved(ctx);
        clients.remove(ctx.channel()); // 這句話沒有必要寫
        System.out.println("客戶端斷開, Channel 對應的長 ID 爲: " + ctx.channel().id().asLongText());
        System.out.println("客戶端斷開, Channel 對應的短 ID 爲: " + ctx.channel().id().asShortText());
    }
}

5. 前端

<template>
  <div id="style">
    <div class="message">
      <el-input
        placeholder="請輸入內容"
        v-model="sendMessage"
        clearable>
      </el-input>
      <br />
      <br />
      <el-button type="primary" @click="sendWebSocket(sendMessage)">發送</el-button>
      <br />
      <br />
      <span>{{receiveMessage}}</span>
    </div>
  </div>
</template>

<script>
  import ElInput from '../../../node_modules/element-ui/packages/input/src/input.vue'
  import ElButton from '../../../node_modules/element-ui/packages/button/src/button.vue'

  export default {
    components: {
      ElButton,
      ElInput
    },
    props: {},
    data () {
      return {
        receiveMessage: '',
        sendMessage: '',
        webSocket: null
      }
    },
    mounted () {},
    watch: {},
    created () {
      this.initWebSocket()
    },
    destroyed () {
      // 離開路由之後斷開 webSocket 連接
      this.webSocket.close()
    },
    methods: {
      // 初始化 webSocket
      initWebSocket () {
        // 創建 WebSocket 對象
        this.webSocket = new WebSocket('ws://127.0.0.1:8009/ws')
        this.webSocket.onopen = this.onOpenWebSocket
        this.webSocket.onmessage = this.onMessageWebSocket
        this.webSocket.onerror = this.onErrorWebSocket
        this.webSocket.onclose = this.closeWebSocket
      },
      // 連接建立之後執行 send 方法發送數據
      onOpenWebSocket () {
        console.log('鏈接建立成功!')
        this.sendWebSocket('鏈接建立成功')
      },
      // 連接建立失敗重連
      onErrorWebSocket () {
        this.initWebSocket()
      },
      // 數據接收
      onMessageWebSocket (e) {
        this.receiveMessage = e.data
      },
      // 數據發送
      sendWebSocket (Data) {
        this.webSocket.send(Data)
      },
      // 關閉
      closeWebSocket (e) {
        console.log('斷開連接', e)
      }
    }
  }
</script>

<style scoped>
  #style {
    width: 700px;
    margin: auto;
  }
</style>

6. 瀏覽效果

瀏覽器

在這裏插入圖片描述

控制檯

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章