【WebSocket应用解析】看完了还敢说不懂WebSocket吗?

1,871 阅读3分钟

本文始发于我的个人网站:www.jianfengke.com/

WebSocket是啥

Websocket是一个持久化的网络通信协议,可以在单个 TCP 连接上进行全双工通讯,没有了Request和Response的概念,两者地位完全平等,连接一旦建立,客户端和服务端之间实时可以进行双向数据传输.

WebSocket跟Http区别与联系

  • HTTP是非持久的协议,客户端想知道服务端的处理进度只能通过不停地使用 Ajax进行轮询或者采用 long poll 的方式来,但是前者对服务器压力大,后者则会因为一直等待Response造成阻塞
  • websocket是独立于HTTP的一种协议,但是websocket必须依赖 HTTP 协议进行一次握手(在握手阶段是一样的),握手成功后,数据就直接从 TCP通道传输,与 HTTP 无关

WebSocket应用

得益于Websocket全双工通信机制,WebSocket可以做弹幕、消息订阅、多玩家游戏、协同编辑、股票基金实时报价、视频会议、在线教育、聊天室等应用实时监听服务端变化。

快速上手WebSocket用法,包括客户端与服务端

首先,我们想搞个这样的东西:

  1. 客户端(前端页面,可多个,代表不同用户)与服务器建立socket连接,建立连接时客户端及服务端都有反应(如输出:加入websocket连接)
  2. 客户端发送消息,服务端接受到信息后,发送特定的消息返回对应客户端
  3. 任一客户端发送消息,服务端接受到信息后,广播到所有客户端

首先我们来实现功能1 我们借助的工具很简单,一个socket包: ws 我们从头安装来应该是这样:

新建文件夹,如命名socket-test,进入该目录
mkdir socket-test
cd socket-test
建立index.js文件,用于启动服务端socket服务
touch index.js
初始化npm,并安装ws
npm init -y
npm i ws
根据ws的文档,快速启动一个websocket服务,如指定启动在9003端口
const WebSocket = require('ws');
 
const wss = new WebSocket.Server({
  port: 9003
})

wss.on("connection", ws => { //监听到有客户端连接上该socket服务时的回调,ws的相关接口操作是针对当前发送信息的客户端
  console.log('加入websocket连接')
  ws.on('open', () => { //当监听到连接已开启时,给对应的客户端返回连接成功的提示
    ws.send('连接已开启');
  });
  ws.on('message', (data) => { //连接上就开始启动对该客户端的监听,一旦有消息发送过来立马触发回调
    ws.send(`你发的消息是:${data}`)
  });
})

就这样,一个简易的websocket服务端就搞好了,你没看错,就这几行代码。

初始化一个客户端页面:

好的现在来初始化一个客户端页面: 在同目录下建立的client1.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>客户端1</title>
</head>
<body>
  
</body>
<script>
  let ws = new WebSocket("ws://localhost:9003")
  ws.onopen = () => {
    console.log('已开启')
  }
  ws.onmessage = event => {
    console.log('客户端1收到服务端消息:', event.data)
  }
  ws.onclose = () => {
    console.log('已关闭');
  }
</script>
</html>
启动服务

好的,到现在客户端跟服务端都已经好的,分别启动吧. 启动服务端:

node index.js  
或nodemon index.js(推荐)

启动客户端: 直接通过liveServer插件就可启动该页面(liveServer为vscode启动页面服务的一个插件,不懂得可自查)

现在都启动了:
服务端输出提示 客户端提示:

WebSocket实例

我们来看下客户端websocket实例都包含了啥:

WebSocket构造函数是浏览器原生接口,专用于进行websocket通信,连接方式也很简单,把服务端地址作为构造参数传进去,然后实例化便完成了websoket的连接。不了解WebSocket的可以点这里看下文档介绍以及用法:WebSocket doc
我们可观察上图实例中的一些属性与方法,可见onclose,onmessage这些已经给定义了回调方法,url属性代表当前websocket连接的地址是什么。重点要关注的是客户端如何向服务端发消息。很简单,实例有个send方法,直接把消息作为send的参数执行便可发送消息。

客户端发送消息

如现在来给服务端发个消息:

ws.send('你好鸭')

发送后服务端接收到消息后立即返回:

没错,这就是socket进行通信的基础流程,聊天室原理跟这个差不多就是一样的了

实现广播功能

如果当前有多个客户端,任一个客户端发来消息,服务端都把消息广播到所有客户端,这怎么做呢?

首先加多一个客户页面,client2.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>客户端2</title>
</head>
<body>
  
</body>
<script>
  let ws = new WebSocket("ws://localhost:9003")
  ws.onopen = () => {
    console.log('已开启')
  }
  ws.onmessage = event => {
    console.log('客户端2收到服务端消息:', event.data)
  }
  ws.onclose = () => {
    console.log('已关闭');
  }
</script>
</html>

需要明确的是,默认情况下,哪个客户端实例给服务端发送了消息,服务端是可感知的,执行ws.send是也是只会针对对应的客户端发送,不会影响其他客户端。

想实现广播功能,需要对服务端进行一个小改造:

const WebSocket = require('ws');
 
const wss = new WebSocket.Server({
  port: 9003
})

wss.on("connection", ws => { //监听到有客户端连接上该socket服务时的回调,ws的相关接口操作是针对当前发送信息的客户端
  console.log('加入websocket连接')
  ws.on('open', () => { //当监听到连接已开启时,给对应的客户端返回连接成功的提示
    ws.send('连接已开启');
  });
  ws.on('message', (data) => { //连接上就开始启动对该客户端的监听,一旦有消息发送过来立马触发回调
    //  取得所有连接中的 客户端
      let clients = wss.clients;
      //循环,发送消息至每个客户端
      clients.forEach((client) => {
          client.send(`你发的消息是:${data}`);
      });
  });
})

核心是通过wss.clients回去当前已连接的客户端实例,遍历发送消息 现在从客户端1发送消息看看客户端2能不能收到。
客户端1: 客户端2:

可见,两者都收到了服务端的广播信息 这就完成了消息的广播

结尾

经过这么一个小栗子鼓捣一下,是不是对WebSocket明白了许多?其实它的功能远不止于此,大家多去发掘,记得有啥好的实践记得推荐给我啊,加油加油。。。。

本文使用 mdnice 排版