乐趣区

关于前端:jsliang-求职系列-28-WebSocket

一 目录

不折腾的前端,和咸鱼有什么区别

目录
一 目录
二 前言
三 WebSocket 和 HTTP
 3.1(短)轮询(Polling)
 3.2 长轮询
 3.3 WebSocket
 3.4 两者比对
四 Socket.io
 4.1 服务端代码
 4.2 客户端代码
 4.3 小结
五 参考文献

二 前言

返回目录

WebSocketHTML5 新增的一种全双工通信协议,客户端和服务器基于 TCP 握手连贯胜利后,两者之间就能够建设持久性的连贯,实现双向数据传输。

三 WebSocket 和 HTTP

返回目录

咱们晓得 HTTP 协定是一种单向的网络协议,在建设连贯后,它容许客户端向服务器发送申请资源后,服务器才会返回相应的数据,而服务器不能被动推送数据给客户端。

过后为什么这样设计呢?假如一些不良广告商被动将一些信息强行推送给客户端,这不得不说是一个劫难。

所以当初咱们要做股票的实时行情,或者获取火车票的残余票数等,就须要客户端和服务器之间重复地进行 HTTP 通信,客户端一直地发送 GET 申请,去获取以后的实时数据。

上面介绍几种常见的形式。

3.1(短)轮询(Polling)

返回目录

短轮询模式下,客户端每隔一段时间向服务器发送 HTTP 申请。

服务器收到申请后,将最新的数据发回给客户端。

这种状况下的弊病是非常明显的:某个时间段服务器没有更新内容,然而客户端每隔一段时间发送申请来询问,而这段时间内的申请是有效的。

这就导致了网络带宽的节约。

3.2 长轮询

返回目录

长轮询模式下,客户端向服务器发出请求,服务器并不一定会立刻回应客户端,而是查看数据是否有更新。

如果数据更新了的话,那就立刻发送数据给客户端;如果没有更新,那就放弃这个申请,期待有新的数据到来,才将数据返回给客户端。

如果服务器长时间没有更新,那么一段时间后,申请变会超时,客户端收到音讯后,会立刻发送一个新的申请给服务器。

当然这种形式也有弊病:当服务器向客户端发送数据后,必须期待下一次申请能力将新的数据收回,这样客户端接管新数据就有一个最短时间距离。

如果服务器更新频率较快,那么就会呈现问题。

3.3 WebSocket

返回目录

基于后面的状况,为了彻底解决服务器被动向客户端发送数据的问题。

W3CHTML5 中提供了一种让客户端与服务器之间进行全双工通信的网络技术 WebSocket

WebSocket 基于 TCP 协定,是一种全新的、独立的协定,与 HTTP 协定兼容却不会融入 HTTP 协定,仅仅作为 HTML5 的一部分。

3.4 两者比对

返回目录

基于下面,小伙伴们大略理解了 WebSocket 的原因了,这里再总结比照一下 HTTPWebSocket

  • 相同点
  1. 都须要建设 TCP 连贯
  2. 都属于七层协定中的应用层协定
  • 不同点
  1. HTTP 是单向数据流,客户端向服务器发送申请,服务器响应并返回数据;WebSocket 连贯后能够实现客户端和服务器双向数据传递,除非某一端断开连接。
  2. HTTPurl 应用 http// 或者 https// 结尾,而 WebSocketurl 应用 ws// 结尾

四 Socket.io

返回目录

咱们先来看 WebSocket 的一个应用形式:

const ws = new WebSocket("ws//:xxx.xx", [protocol])

ws.onopen = () => {ws.send('hello')
  console.log('send')
}

ws.onmessage = (ev) =>{console.log(ev.data)
  ws.close()}

ws.onclose = (ev) =>{console.log('close')
}

ws.onerror = (ev) =>{console.log('error')
}

WebSocket 实例化后,前端能够通过下面介绍的办法进行对应的操作,看起来还是蛮简略的。

然而,如果想齐全搭建一个 WebSocket 服务端比拟麻烦,又浪费时间。

所以:Socket.io 基于 WebSocket,加上轮询机制以及其余的实时通信方面的内容,实现的一个库,它在服务端实现了实时机制的响应代码。

也就是说,WebSocket 仅仅是 Socket.io 实现通信的一个子集。

因而,WebSocket 客户端连贯不上 Socket.io 服务端,Socket.io 客户端也连不上 WebSocket 服务端。

上面咱们解说下如何实现一个简略的聊天。

4.1 服务端代码

返回目录

package.json

{
  "devDependencies": {
    "express": "^4.15.2",
    "socket.io": "^2.3.0"
  }
}

index.js

let express = require('express');
let app = express();
let server = require('http').createServer(app);
let io = require('socket.io')(server);
let path = require('path');

app.use('/', (req, res, next) => {res.status(200).sendFile(path.resolve(__dirname, 'index.html'));
});

// 开启 socket.io
io.on('connection', (client) => {

  // 如果有新客户端进来,显示 ID
  console.log(` 客户端 ID:${client.id}`);

  // 监听客户端的输出信息
  client.on('channel', (data) => {console.log(` 客户端 ${client.id} 发送信息 ${data}`);
    io.emit('broadcast', data);
  });

  // 判断客户端是否敞开
  client.on('disconnect', () => {console.log(` 客户端敞开:${client.id}`);
  });
});

server.listen(3000, () => {console.log('服务监听 3000 端口');
});

如上,咱们间接通过 npm i 装置依赖包后,间接通过 node index.js 能够开启服务。

当然,如果小伙伴们想手动装包,执行上面命令即可:

npm i express socket.io express -D

4.2 客户端代码

返回目录

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Socket.io</title>
  <script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.slim.js"></script>
</head>

<body>

  <input type="text" id="input">
  <button id="btn">send</button>
  <div id="content-wrap"></div>

  <script>
    window.onload = function () {
      let inputValue = null;

      // 连贯 socket.io
      let socket = io('http://localhost:3000');
      // 将创立的信息以增加 p 标签的模式展现成列表
      socket.on('broadcast', data => {let content = document.createElement('p');
        content.innerHTML = data;
        document.querySelector('#content-wrap').appendChild(content);
      })

      // 设置输入框的内容
      let inputChangeHandle = (ev) => {inputValue = ev.target.value;}
      // 获取输入框并监听输出
      let inputDom = document.querySelector("#input");
      inputDom.addEventListener('input', inputChangeHandle, false);

      // 当用户点击发送信息的时候,进行数据交互
      let sendHandle = () => {socket.emit('channel', inputValue);
      }
      let btnDom = document.querySelector("#btn");
      btnDom.addEventListener('click', sendHandle, false);

      // 打页面卸载的时候,告诉服务器敞开
      window.onunload = () => {btnDom.removeEventListener('click', sendHandle, false);
        inputDom.removeEventListener('input', inputChangeHandle, false);
      }
    };
  </script>
</body>

</html>

4.3 小结

返回目录

Socket.io 不仅反对 WebSocket,还反对许多种轮询机制以及其余实时通信形式,并封装了通用的接口。

这些形式蕴含 Adobe Flash SocketAjax 长轮询、Ajax multipart streaming、长久 IframeJSONP 轮询等。

换句话说,当 Socket.io 检测到以后环境不反对 WebSocket 时,可能主动地抉择最佳的形式来实现网络的实时通信。

这样,咱们就对 WebSocket 有肯定的理解,面试的时候就不慌了。

五 参考文献

返回目录

  • [x] websocket 与 Socket.IO 介绍【浏览倡议:10min】
  • [x] WebSocket 与 Socket.IO【浏览倡议:10min】
  • [x] Websocket 和 Socket.io 的区别及利用【浏览倡议:20min】

jsliang 的文档库由 梁峻荣 采纳 常识共享 署名 - 非商业性应用 - 雷同形式共享 4.0 国内 许可协定 进行许可。<br/> 基于 https://github.com/LiangJunrong/document-library 上的作品创作。<br/> 本许可协定受权之外的应用权限能够从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处取得。

退出移动版