websocket 是一种基于http的通信协议,服务端可以主动推送信息给客户端,客户端也可以像服务端发送请求,Websocket允许服务端与客户端进行全双工通信。

特点

  • 基于tcp协议之上,服务端实现比较容易

  • 默认端口是80(ws)或者443(wss),握手阶段采用的http协议

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

  • 可以发送文本或者二进制数据

  • 没有同源限制,客户端可以像任意服务发送信息

  • 协议标识符是ws,如果加密,那么是wss,

实现客户端与服务端通信

新建一个html文件客户端代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>websocket</title>
  </head>
  <body>
    <h3>hello websocket</h3>
    <input type="number" id="textContent" />
    <button id="handleSend">发送</button>
    <button id="auto-send">开启服务端向客户端发消息模式</button>
    <hr />
    <div id="app"></div>
  </body>
</html>

html中引入下面一段 js

// index.js
const sendDom = document.getElementById('send');
const appDom = document.getElementById('app');
const autoDom = document.getElementById('auto-send');
const inputContent = document.getElementById('textContent');
const socketPath = 'ws://192.168.31.40:3000';
let timer = null;
let num = 0;
const result = [];
// 建立连接
const ws = new WebSocket(socketPath);
const sendMyNum = (isSetInterval = false, to = 'client', val) => {
  const setNum = () => {
    num = val || Math.ceil(Math.random() * 10);
    ws.send(
      JSON.stringify({
        clientText: `client:hello,我是${num}`,
        num,
        to
      })
    );
  };
  if (isSetInterval) {
    timer = setInterval(() => {
      setNum();
    }, 1000);
  } else {
    setNum();
  }
};
const renderHtml = (data) => {
  const { serverText, clientText } = JSON.parse(data);
  appDom.innerHTML = '';
  result.push({
    serverText,
    clientText
  });
  console.log(result);
  if (result.length > 0) {
    let str = '';
    result.forEach((v) => {
      str += `<ul>
              <li>${v.clientText}</li>
              <li>${v.serverText}</li>
            </ul>`;
    });
    appDom.innerHTML = str;
  }
};
// 发送数据
ws.onopen = function () {
  console.log('websocket connection start');
  sendMyNum(false);
};
// 接收服务端发送的消息
ws.onmessage = function (evt) {
  console.log(`receive:${evt.data}`);
  if (evt.data) {
    renderHtml(evt.data);
    // 接收数据后关闭定时器
    clearInterval(timer);
    // sendMyNum(true)
  }
};
// 关闭连接
ws.onclose = function () {
  console.log('关闭了');
};
// 手动向客户端发送消息
handleSend.onclick = function () {
  const val = inputContent.value;
  if (val === '') {
    alert('请输入你的编号');
    return;
  }
  sendMyNum(false, 'client', val);
};
// 自动开启向客户端发送消息
autoDom.onclick = function () {
  sendMyNum(true, 'server');
};

新建一个server目录,新建创建服务端代码,主要依赖nodejs-websocketopen in new window这个库是服务端websocket代码。

var ws = require('nodejs-websocket');
var http = require('http');
const fs = require('fs');
const path = require('path');
const PORT = 8080;
var server = http.createServer(function (request, response) {
  response.statusCode = 200;
  response.setHeader('Content-Type', 'text/html');
  fs.readFile(path.resolve(__dirname, '../', 'index.html'), (err, data) => {
    if (err !== null) {
      response.end('404');
      return;
    }
    response.end(data);
  });
});
server.listen(PORT, function (evt) {
  console.log(new Date() + ' Server is listening on port 8080');
});

// websocket
const tcp = ws
  .createServer(function (connection) {
    console.log('New connection');
    connection.on('text', function (data) {
      const { clientText, num, to } = JSON.parse(data);
      if (to === 'server') {
        connection.sendText(
          JSON.stringify({
            serverText: `server:${num}号,恭喜你,你太幸运了,你已经被清华录取了`,
            clientText: `${num}`
          })
        );
      } else {
        if (num > 6) {
          connection.sendText(
            JSON.stringify({
              clientText,
              serverText: `server:${num}号,你非常优秀, ${num}号,你已经成功被录取了北京大学`
            })
          );
        } else {
          connection.sendText(
            JSON.stringify({
              serverText: `server: ${num}号,非常遗憾,${num}号,你落榜了,再接再厉`,
              clientText
            })
          );
        }
      }
    });
    connection.sendText(
      JSON.stringify({
        serverText: `server:hello,我们已经建立连接了`,
        clientText: `client:你好`
      })
    );
    connection.on('close', function (code, reason) {
      console.log('Connection closed');
      console.log(code, reason);
    });
  })
  .listen(3000);

tcp.on('error', (err) => {
  console.log(err);
});

我们可以执行命令node server.js,打开浏览器http://localhost:8080/ 打开network,ws下面可以看到有客户端向服务端发送的消息,也有服务端向客户端发送的两条信息。

我们看到请求头的一些信息

我们可以看到请求头里

General

Request URL: ws://192.168.31.40:3000/
Request Method: GET
Status Code: 101 Switching Protocols

Request Headers

Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: no-cache
Connection: Upgrade
Host: 192.168.31.40:3000
Origin: http://localhost:8080
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: Mk8Au85XqQTn+vuDsfr/kw==
Sec-WebSocket-Version: 13
Upgrade: websocket
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36

当输入数字,向服务端发送消息时,服务端会返回对应信息。通常来讲,服务端会不定时的向前端推送信息,前端拿到推送信息进行一系列的页面状态展示等。

通过以上的例子,我们基础的了解到websocket的使用

总结

websocket其实需要客户端对websocket处理主要是这三个步骤

更多websocket可以参考websocketopen in new window

扫二维码,关注公众号
专注前端技术,分享web技术
加作者微信
扫二维码 备注 【加群】
教你聊天恋爱,助力脱单
微信扫小程序二维码,助你寻他/她
专注前端技术,分享Web技术
微信扫小程序二维码,一起学习,一起进步
前端面试大全
海量前端面试经典题,助力前端面试