1_websocket工具封装

Websocket

前言

  1. 为什么需要 WebSocket?

    • http协议通信只能由客户端发起。若服务器有连续的状态变化,客户端需要通过“轮询”才可获知

    轮询的效率低,非常浪费资源(需要不停连接,或者http连接始终打开)

  2. WebSocket 最大的特点:服务器可以主动向客户端推送消息,客户端也可以主动向服务器发送消息,是双向平等对话,属于服务器推送技术的一种。

  3. WebSocket 其它特点

    1. 建立在TCP协议之上,服务端的实现比较容易

    2. 与http协议有着良好的兼容性。默认端口是80和443,并且握手阶段采用http协议

    3. 数据格式比较轻量,性能开销小,通信高效

    4. 可以发送文本,也可以发送二进制数据

    5. 没有同源限制,客户端可以与任意服务器通信

    6. 协议标识符是ws,服务器网址就是url
      ws://example.com:80/some/path

1 构造函数

  • new WebSocket(url[, protocols])

  • 参数

    • url:要连接到的 URL
    • protocols:单个协议字符串或协议字符串数组

2 实例属性

  • binaryType:接收的二进制数据的类型

    • blob
    • arraybuffer
  • readyState:websocket 连接的当前状态

readyState 值 mean 解释
0 connecting 已创建 socket,连接尚未打开
1 open 连接打开且已做好通信准备
2 closing 连接正在关闭
3 closed 连接已关闭

3 实例方法

  • close():关闭连接

    • close(code, reason)

    • 参数

      • code :指示关闭原因
        • 1000:正常关闭
        • 1001-1015:指示实际原因
  • send(data):发送数据

4 事件

  1. close:websocket 连接关闭时触发 close 事件

    • addEventListener("close", (event) => {});

    • onclose = (event) => {};

    • 属性

      • code:服务器发送的关闭代码
      • reason:服务器关闭连接的原因
      • wasClean:是否已完全关闭
  2. error:与 websocket 连接由于错误而关闭时触发 error 事件

    • addEventListener("error", (event) => {});
    • onerror = (event) => {};
  3. message:websocket 接收到数据时触发 message 事件

    • addEventListener("message", (event) => {});

    • onmessage = (event) => {};

    • 属性

      • data
      • origin:消息来源
  4. open:与 websocket 建立连接时触发 open 事件

    • addEventListener("open", (event) => {});
    • onopen = (event) => {};
import { useState, useRef, useEffect } from 'react';

interface WebSocketOptions {
  url: string;
  onOpen?: () => void;
  onMessage?: (message: any) => void;
  onClose?: (event: Event) => void;
  onError?: (event: Event) => void;
  reconnectInterval?: number;
  reconnectAttrmpts?: number;
}

const defaultOptions: Required<WebSocketOptions> = {
  url: '', // 连接的长连接
  onOpen: () => {}, // 开启连接
  onMessage: () => {}, // 消息
  onClose: () => {}, // 关闭连接
  onError: () => {}, // 异常
  reconnectInterval: 1000, // 重连时长设置
  reconnectAttrmpts: Number.MAX_VALUE // 最大连接范围数
};

const useWebsocket = (options: WebSocketOptions): [WebSocket | undefined, (message: any) => void, string, boolean] => {
  const { url, onOpen, onClose, onMessage, onError, reconnectInterval, reconnectAttrmpts } = {
    ...defaultOptions,
    ...options
  };

  const [isConnected, setIsConnected] = useState(false); // 是否连接
  const [reconnectCount, setReconnectCount] = useState(0); // 是否重连
  const [newMessage, setNewMessage] = useState(''); // 最新消息

  const wsRef = useRef<WebSocket>();
  const reconnectTimerRef = useRef<NodeJS.Timer>();

  const connect = () => {
    setIsConnected(false);

    const ws = new WebSocket(url);

    // 与 websocket 建立连接时触发
    ws.onopen = () => {
      console.log('----------websocket is connected---------');
      setIsConnected(true);
      setReconnectCount(0);
      onOpen();
    };

    // websocket 接收到数据时触发
    ws.onmessage = event => {
      const message: any = JSON.parse(event.data);
      console.log(`----------websocket reveived message: ${message}--------------`);
      setNewMessage(event.data);
      onMessage(message);
    };

    // websocket 连接关闭时触发
    ws.onclose = event => {
      console.error(`-----------wesocket closed with code ${event.code}-----------`);
      setIsConnected(false);
      onClose(event);

      // 是否重新连接
      // if (reconnectCount < reconnectAttrmpts) {
      //   reconnectTimerRef.current = setTimeout(() => {
      //     setReconnectCount(prevCount => prevCount + 1);
      //     connect();
      //   }, reconnectInterval);
      // }
    };

    // 与 websocket 连接由于错误而关闭时触发
    ws.onerror = event => {
      console.error(`websocket error:`, event);
      onClose(event);
    };
    wsRef.current = ws;
  };

  useEffect(() => {
    connect();
    return () => {
      // 关闭连接
      wsRef.current?.close();
      clearTimeout(reconnectTimerRef.current);
    };
  }, []);

  const sendMessage = (message: any): void => {
    if (isConnected && wsRef.current) {
      console.log(`-------websocket sending message: ${JSON.stringify(message)}--------`);
      // 发送数据
      wsRef.current.send(JSON.stringify(message));
    } else {
      console.error('cannot send message - websocket is not connected');
    }
  };

  return [wsRef.current, sendMessage, newMessage, isConnected];
};
export default useWebsocket;

posted on 2024-06-11 11:54  pleaseAnswer  阅读(2)  评论(0编辑  收藏  举报