前端使用WebSockets通信

17,027 阅读5分钟

WebSockets通信

一.WebSockets通信的基本知识

WebSockets是HTML5提供的在WEB应用程序中客户端和服务器端之间进行的非HTTP的通信机制。他实现了用HTTP不容易实现的服务器端的数据推送等智能通信技术,因此受到了告诉关注。

使用WebSockets 建立的连接是实时的,也是永久的,除非被显示关闭。这意味着当服务器想向客户端发送数据时,可以立即将数据推送到客户端的浏览器中,无需再重新建立连接。只要客户端有一个被打开的socket(套接字)与服务器连接,服务器就会把数据发送到这个socket中,服务器不需要再轮询客户端的请求,从被动转为了主动。

另外,在WebSocket API中,同样可以使用跨域通信技术,在使用跨域通信技术时,应该确保客户端与服务器端是互相信任的,服务器端应该判断将他的服务数据发送给所有客户端还是只发送给某些受信任的客户端。

二.使用WebSokets API

WebSockets的API比较简单也比较少,就几个,很好理解:

第一个:创建Websocket 对象,参数是URL,注意的是URL是以ws或wss开头的,例如:

var ws = new WebSocket("ws://localhost:8080/socket")

第二个:发送数据,Websocket只能发送文本数据,如果是对象的话,必须得转成文本数据再发送,后面 专门会将:

ws.send("我是客户端发送的数据")

第三个:通过onopen事件句柄来监听websockets的连接状态:

ws.onopen = function(event){
    //开始通信时的处理
}

第四个:通过获取onmessage事件句柄来获取服务端发送过来的数据,如:

ws.onmessage = function(event){
    console.log(event.data)
}

第五个:通过onclose事件句柄来监听websockets的关闭状况:

ws.onclose = function(event){
	//关闭时的处理操作
}

三.WebSockets API 使用示例

第六个:close来主动关闭websockets:

ws.close();

另外,可以通过readyState来获取WebSockets的连接状态:

CONNECTING:值为0,代表正在连接;
OPEN:值为1,代表里已经连接;
CLOSING:值为2,代表正在关闭;
CLOSED:值为3,代表已关闭。

三.WebSockets的使用示例

下面通过一个简单的例子看一下websockets的使用示例,后端的服务用的node.js写的,其他的语言都可以实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <h1>websockets简单示例</h1><br>
    <div id="message"></div>
    <div>
        <input type="text" id="sendText">
        <button id="connect" onclick="connect()">建立连接</button>
        <button id="sendData" onclick="sendData()">发送数据</button>
        <button id="closeConnect" onclick="closeConnect()">关闭连接</button>
    </div>
</body>
<script type="text/javascript">
    let websockets;
    //创建一个数组对象用于存放当前的连接的状态,以便在页面上实时展示出来当前的状态
    let statusArr = [
        { state: 0, value: '正在连接' },
        { state: 1, value: '已建立连接' },
        { state: 2, value: '正在关闭连接' },
        { state: 3, value: '已关闭连接' },
    ]
    /**
    *   建立连接
    *
    */
    function connect() {
        // 1. 创建websockets对象,参数为服务器websockets地址
        websockets = new WebSocket("ws:127.0.0.1:7001");

        // 2.监听websocket的状态变化,接收的信息,关闭时的状态

        //监听连接状态的变化
        websockets.onopen = (event) => socketChange();

        //监听接收消息的情况
        websockets.onmessage = (res) => {
            document.querySelector("#message").innerHTML += `<p>接收数据: ${res.data}</p>`
        }

        //监听关闭时的状态变化
        websockets.onclose = (event) => socketChange();
    }
    /**
    *   socket状态变化
    *
    */
    function socketChange() {
        let state = websockets.readyState;
        let val = statusArr.map((item) => {
            if (item.state == state) {
                return item.value
            }
        });

        //实时显示状态的变化
        document.querySelector("#message").innerHTML += `<p>当前的socket连接状态是: ${val}</p>`
    }
    /**
    *   发送数据
    *
    */
    function sendData() {
        //1. 首先获取输入的信息,判断信息是否可以发送
        let val = document.querySelector("#sendText").value;

        if (val == "" || val == undefined) {
            document.querySelector("#message").innerHTML += "<p>发送数据为空,请填写完成后再发送!</p>";
            return;
        }

        websockets.send(val);
        document.querySelector("#message").innerHTML += `<p>发送数据:${val}</p>`;
    }
    /**
    *   关闭连接
    *
    */
    function closeConnect() {
        websockets.close();
    }
</script>

</html>

服务端node.js,引入nodejs-websocket包:

let wx = require ('nodejs-websocket');
//建立连接
let server = wx
  .createServer (conn => {
    conn.on ('text', str => {
      console.log (`客户端发送过来的数据:${str}`);
      let dataArr = ['帅', '美', '漂亮', '智能', '好看', '大方'];
      let curVal = '';
      let res = dataArr.reduce ((last, cur) => {
        let val;
        if (str.indexOf (cur) != -1) {
          val = 1;
          curVal = cur;
        } else {
          val = 0;
        }
        return last + val;
      }, 0);
      console.log (res);
      if (res != 0) {
        conn.sendText (`${curVal},很${curVal},非常${curVal}`);
      } else {
        conn.sendText ('我太笨了,不知道你说的是啥,不要为难我');
      }
    });

    conn.on ('close', (code, reason) => {
      console.log ('关闭连接');
    });

    conn.on ('error', (code, reason) => {
      console.log ('连接异常');
    });
  })
  .listen (7001);

四.发送对象

上面的示例显示websocke互相发送文本数据的示例,发送对象的话需要通过 JSON.parse() 和JSON.Stringify()来转换成字符串发送,接收到之后解析字符串来实现,当然还有其他的方式,只要把对象转成字符串就可以发送:

<script type="text/javascript">
    let websockets = new WebSocket("ws:127.0.0.1:7001");
     websockets.onmessage = (event) => {
         let data = JSON.parse(event.data) ;
         console.log(data);
         websockets.send(JSON.Stringify({
             title:'发送对象数据',
             time:+new Date()
         }))
     }
    
</script>

五.发送与接收原始二进制数据

除了能发送文本信息和普通对象信息之外,还可以发送ArrayBuffer对象和Blob对象;接收ArrayBuffer和Blob对象的时候需要把类型设置成arraybuffer和blob才可以接收,下面看一个示例:

<!DOCTYPE html>
<html>
<body>

<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>

<script>
let websockets = new WebSocket("ws:127.0.0.1:7001");
let ctx=document.getElementById("myCanvas").getContext("2d");
let imgData=ctx.getImageData(10,10,50,50);
let binary = new UnitArray(imgData.data.length);

 for(let i = 0; i<imgData.data.length;i++){
     binary[i] = imgData.data[i];
  }
 //发送数据
  websockets.send(binary.buffer);
    
  //接收数据
  websockets.binaryType = "arraybuffer";
  websockets.onmessage = (event) => {
      let data = JSON.parse(event.data) ;
      console.log(event.data.byteLength);
    
  }
</script>
</body>
</html>

六.WebSockets API的使用场景

WebSockets适用于多个客户端和一个服务器端实现实时通信的场合,例如:

  • 多人在线游戏网站
  • 在线聊天室
  • 实时体育或者新闻评论网站
  • 实时交互用户信息的社交网站