3分钟快速入门WebSocket

目录

WebSocket是什么?

这两种协议有什么区别?

那服务端如何判断本次的协议是HTTP还是WebSocket呢?

demo


WebSocket是什么?

它和HTTP协议类似,都是基于TCP协议的

HTTP和WebSocket是网络通讯协议

这两种协议有什么区别

HTTP1.1:是半双工的,在同一时刻只能一方发送数据给另一方。HTTP协议是一种'请求-响应'模式,只能通过客户端发送http请求,接受服务端http响应,以此来传输数据,服务端不能主动给客户端发送信息
WebSocket:是全双工的,在同一时刻能同时发送数据,一旦客户端和服务端建立了TCP连接,二者就能时刻保持通讯状态。

举个例子:

我们在访问一个网址 时,客户端需要向目标服务器请求网页资源,此时客户端向服务器发送http请求,发送之前二者需要建立TCP连接,服务端接受到请求后,做出响应,返回给客户端所需的资源,之后二者关闭TCP连接。如果再需要向服务端请求资源,就需要重新建立TCP连接,并发送http请求,服务端响应完毕后,二者关闭TCP连接。

这是HTTP的使用场景,而有一些场景,例如扫码登录

当用户扫码后,用户信息传递给服务端,由于HTTP协议1.1不支持服务端主动向客户端发送数据,所以客户端需要不断向服务端发送查询请求,来询问服务器用户是否扫码,这实现方式就是轮询。

**短轮询:**客户端每隔一定时间间隔向服务端发送查询请求,例如每隔1秒发送查询请求。
**长轮询:**客户端发送查询请求后,该请求会保持挂起状态一段时间(例如保持30秒),如果用户在这30秒内还没有扫码,服务端就返回一个空响应,客户端会重新发送查询请求。

长轮询避免 了在用户扫码前发送过多的查询请求消耗过多的资源 ,又能保证实时处理用户操作,从而实现用户享受无感知服务器推送 功能。

在这种场景下,WebSocket更适配

那服务端如何判断本次的协议是HTTP还是WebSocket呢?

通过TCP建立客户端和服务端的连接后,客户端发送http请求

完整http请求包含必要的请求行、请求头、请求体
请求行:

  1. 请求方法 (GET/POST/PUT/DELETE...)

  2. 请求路径url

  3. 协议邦本
    请求头字段:
    Host :目标服务器的域名和端口(必需)
    User-Agent :客户端(浏览器 / APP)的身份信息
    Content-Type :声明请求体的数据格式
    Authorization :身份验证信息(token)

...
请求体:

当需要向服务端发送数据时存在,最常用的就是以json格式传送数据

复制代码
{
  "username": "admin",
  "password": "123456",
}
  1. WebSocket在建立TCP连接后,需要发送一个特殊的http请求

这个http请求必须包含以下特定字段
Upgrade: websocket

关键升级字段:告诉服务器 "我想把协议从 HTTP 升级到 WebSocket",值必须是 `websocket`(大小写不敏感,但常规用小写)。
Connection: Upgrade

配合 Upgrade 字段:告诉服务器 "这是一个协议升级请求,不要按普通 HTTP 响应处理",值必须包含 `Upgrade`
Sec-WebSocket-Key:

安全验证字段:客户端生成的随机的base64编码的字符串
Sec-WebSocket-Version指定 WebSocket 协议版本

  1. 服务端接受后,处理该请求并返回响应

如果请求成功,服务端返回101状态码,表示协议切换成功,从http协议切换为websocket协议,

并返回Sec-WebSocket-Accept响应字段。

该字段是服务器根据客户端的 `Sec-WebSocket-Key` 计算得出的值,客户端会验证该值是否正确,若不正确则断开连接(防止伪造响应)。

完成以上操作后,就成功连接websocket了,客户端和服务端就可以进行实时的双向通讯了。

demo

下面我们通过一个demo,用websocket完成一个实时接收服务端返回的数据的小案例

demo演示

  1. 安装node.js

  2. 在编辑器里新建文件夹

    初始化项目

    npm init -y

    安装ws

    npm install ws

  3. 新建server.js文件

javascript 复制代码
// 引入ws库,创建websocket服务器
const WebSocket = require('ws');
// 监听8080端口
const ws = new WebSocket.Server({ port: 8080 });

// 监听用户连接
ws.on('connection', (ws) => {
    console.log('用户连接成功');
    let timer = setInterval(() => {
        ws.send(createRandom());
    }, 1000);

    // 监听客户端发送的信息
    ws.on('message', (message) => {
        console.log('用户信息:', message.toString());
        ws.send(message.toString());
    })

    // 监听客户端是否断开连接
    ws.on('close', () => {
        console.log('用户断开连接');
    })
})

// 生成随机数
const createRandom = () => {
    let num = Math.floor(Math.random()*100);
    return num;
}

console.log('WebSocket 服务器已启动,端口 8080');
  1. 新建index.html文件
javascript 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>websocket</title>
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <div id="box">
      <h3>服务端返回的信息</h3>
      <div id="container"></div>
    </div>
    <div>
      <input type="text" placeholder="输入发送的信息" />
      <button onclick="sentMessage()">发送信息</button>
      <button onclick="closeConnect()">断开连接</button>
    </div>

    <script src="./websocket.js"></script>
  </body>
</html>
  1. 新建websocket.js文件,实现客户端与服务端的连接
javascript 复制代码
const input = document.querySelector("input");
const container = document.getElementById('container');

// 连接websocket服务器
const ws = new WebSocket("ws://localhost:8080");

// 1. 监听连接是否成功
ws.onopen = (e) => {
  console.log("连接信息", e);
};

// 2. 监听服务端发送的信息
ws.onmessage = (msg) => {
  console.log("服务器", msg);
  renderMsg(msg.data);
};

// 3. 监听连接断开
ws.onclose = (e) => {
  console.log("连接断开", e);
};

// 4. 监听连接错误
ws.onerror = (e) => {
  console.log("连接错误", e);
};

// 断开连接
const closeConnect = () => {
  ws.close();
};

// 发送消息到服务端
const sentMessage = () => {
  const msg = input.value.trim();
  if (msg) {
    ws.send(msg);
    input.value = "";
    console.log("发送成功");
  }
};

// 将信息展示到页面
const renderMsg = (msg) => {
    container.innerHTML += `<p>${msg}</p>`;
    container.scrollTo({
      top: container.scrollHeight,
      behavior: 'smooth',
    })
}
  1. 最后附上index.css文件
css 复制代码
#box {
  width: 300px;
  height: 300px;
  text-align: center;
  display: flex;
  flex-direction: column;
}
#box h3 {
  margin: 10px 0;
  flex-shrink: 0;
}
#container {
  width: 100%;
  flex: 1;
  overflow: scroll;
  text-align: center;
  margin-bottom: 10px;
  border: 1px solid black;
}

#container::-webkit-scrollbar {
  display: none; 
}

#box div p {
  text-align: center;
}

到此为止我们就实现啦

相关推荐
码熔burning4 小时前
RPC 和 HTTP 的区别
网络协议·http·rpc
白堤上的喵4 小时前
信息安全基础知识
网络
赖龙5 小时前
记录SSL部署,链路不完整问题
网络·网络协议·ssl
fatiaozhang95275 小时前
浪潮CD1000-移动云电脑-RK3528芯片-2+32G-安卓9-2种开启ADB ROOT刷机教程方法
android·网络·adb·电脑·电视盒子·刷机固件·机顶盒刷机
tang777895 小时前
金融行业:静态与动态代理 IP 的选型与风控
网络·tcp/ip·金融
Xの哲學6 小时前
Linux RCU (Read-Copy-Update) 机制深度分析
linux·网络·算法·架构·边缘计算
吐个泡泡v6 小时前
网络编程基础:一文搞懂 Socket、HTTP、HTTPS、TCP/IP、SSL 的关系
网络·网络协议·http·https·socket·ssl·tcp
Blurpath6 小时前
如何利用静态代理IP优化爬虫策略?从基础到实战的完整指南
爬虫·网络协议·ip代理·住宅代理
liulilittle7 小时前
HTTP简易客户端实现
开发语言·网络·c++·网络协议·http·编程语言