7.计算机网络-Websocket-《前端知识进阶》

admin 2025-11-01 15:42:35 编程 来源:ZONE.CI 全球网 0 阅读模式
  • 1. WebSocket出现前
  • 2. WebSocket 概述
  • 3. WebSocket 特点
  • 4. Websocket的使用
  • 5. WebSocket的API
    • 5.1 WebSocket构造函数
    • 5.2 webSocket.readyState
    • 5.3 webSocket.onopen
    • 5.4 webSocket.onclose
    • 5.5 webSocket.onmessage
    • 5.5 webSocket.send()
    • 5.7 webSocket.bufferedAmount
    • 5.8 webSocket.onerror

    1. WebSocket出现前

    我们知道HTTP协议是半双工通信的,同一时刻数据只能单向流动,而且只能是客户端向服务器发起请求,服务器返回请求结果,服务器不能主动向服务端推送信息。如果我们需要与服务器进行持续的通信以保持双方信息的同步,就需要把不断地刷新页面,进行请求验证,这样就造成一定资源的浪费。在WebSocket出现之前,想要持续的通讯,有以下几种解决方案:(1)短轮询短轮询通常采用setInterval 或者 setTimeout 来实现。每隔一段时间就发送一次ajax请求:

    1. setInterval(function() {
    2. $.get("/path/to/server", function(data, status) {
    3. console.log(data);
    4. });
    5. }, 1000);

    这样就基本实现了每隔一段时间进行一次轮询,但是也存在一定的问题。我们这里设置的请求的时间为,每隔一秒请求一次,如果网络情况不好,一秒钟时间数据还没返回回来,下一个请求就开始了,这就很容易导致数据的顺序错乱,所以可以使用下面的方法:

    1. function poll() {
    2. setTimeout(function() {
    3. $.get("/path/to/server", function(data, status) {
    4. console.log(data);
    5. // 发起下一次请求
    6. poll();
    7. });
    8. }, 1000);
    9. }

    这样设置的话,每次都会在上一次完成的情况下在进行新的请求。(2)长轮询上面的传统的轮询方式存在一个很大的问题,就是每次都会发送一个HTTP请求,然而并不是每次都能返回需要的数据,这无疑造成了资源的浪费,也给服务器带来了很大的负担。这时就可以使用长轮询的方式来解决这个问题。在长轮询机制中,当服务器收到客户端发来的请求后,不会直接进行响应,而是先将这个请求挂起,然后判断服务器端数据是否有更新。如果有更新,则进行响应;如果一直没有数据,则到达一定的时间限制(服务器端设置)才返回。 客户端在处理完服务器返回的信息后,再次发出请求,重新建立连接。长轮询和短轮询相比,明显是减少了很多不必要的HTTP请求,但是,长轮询在建立连接之后会挂起,等待服务端数据的更新,这样也会导致资源的浪费。(3)长连接(SSE)SSE是HTML5新增的功能,全称为Server-Sent Events,也就是服务器发送事件。通过 SSE ,客户端可以自动获取数据更新,而不用重复发送HTTP请求。一旦连接建立,“事件”便会自动被推送到客户端。服务器端SSE通过事件流(Event Stream) 的格式产生并推送事件。客户端中,SSE借由 EventSource 对象实现。EventSource 包含五个外部属性:onerroronmessageonopenreadyStateurl,以及两个内部属性:reconnection timelast event ID string。在onerror属性中可以对错误捕获和处理,而 onmessage 则对应着服务器事件的接收和处理。另外也可以使用 addEventListener 方法来监听服务器发送事件,根据event字段区分处理。

    1. var eventSource = new EventSource("/path/to/server");
    2. eventSource.onmessage = function (e) {
    3. console.log(e.event, e.data);
    4. }
    5. // 或者
    6. eventSource.addEventListener("ping", function(e) {
    7. console.log(e.event, e.data);
    8. }, false);

    SEE的优势在于,它不需要建立或者保持大量客户端发送的请求,节约了资源,提高了应用的性能。但是它只支持单向数据通信,只能从服务端向客户端发送消息。

    2. WebSocket 概述

    WebSocket是HTML5提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。它基于TCP传输协议,并复用HTTP的握手通道。浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接, 并进行双向数据传输。WebSocket 的出现就解决了半双工通信的弊端。它最大的特点是:服务器可以向客户端主动推动消息,客户端也可以主动向服务器推送消息。WebSocket原理:客户端向 WebSocket 服务器通知(notify)一个带有所有接收者ID(recipients IDs)的事件(event),服务器接收后立即通知所有活跃的(active)客户端,只有ID在接收者ID序列中的客户端才会处理这个事件。

    3. WebSocket 特点

    • 支持双向通信,实时性更强
    • 可以发送文本,也可以发送二进制数据‘’
    • 建立在TCP协议之上,服务端的实现比较容易
    • 数据格式比较轻量,性能开销小,通信高效
    • 没有同源限制,客户端可以与任意服务器通信
    • 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL
    • 与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

      4. Websocket的使用

      在客户端中:

      1. // 在index.html中直接写WebSocket,设置服务端的端口号为 9999
      2. let ws = new WebSocket('ws://localhost:9999');
      3. // 在客户端与服务端建立连接后触发
      4. ws.onopen = function() {
      5. console.log("Connection open.");
      6. ws.send('hello');
      7. };
      8. // 在服务端给客户端发来消息的时候触发
      9. ws.onmessage = function(res) {
      10. console.log(res); // 打印的是MessageEvent对象
      11. console.log(res.data); // 打印的是收到的消息
      12. };
      13. // 在客户端与服务端建立关闭后触发
      14. ws.onclose = function(evt) {
      15. console.log("Connection closed.");
      16. };

      这里先不管服务端的实现了,以后学到后端的知识再补充……

      5. WebSocket的API

      5.1 WebSocket构造函数

      WebSocket对象作为一个构造函数,用于新建WebSocket实例:

      1. let ws = new WebSocket('ws://localhost:9999');

      执行上面的语句之后,就会与服务器进行连接。

      5.2 webSocket.readyState

      readyState属性会返回实例对象的当前状态,其值共有四种:

    • CONNECTING:值为0,表示正在连接。

    • OPEN:值为1,表示连接成功,可以通信了。
    • CLOSING:值为2,表示连接正在关闭。
    • CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
      1. switch (ws.readyState) {
      2. case WebSocket.CONNECTING:
      3. // do something
      4. break;
      5. case WebSocket.OPEN:
      6. // do something
      7. break;
      8. case WebSocket.CLOSING:
      9. // do something
      10. break;
      11. case WebSocket.CLOSED:
      12. // do something
      13. break;
      14. default:
      15. // this never happens
      16. break;
      17. }

      5.3 webSocket.onopen

      实例对象的onopen属性用于指定连接成功之后的回调函数:
      1. ws.onopen = function() {
      2. console.log("Connection open.");
      3. ws.send('hello');
      4. };
      如果需要指定多个回调函数,可以使用addEventListener方法:
      1. ws.addEventListener('open', function (event) {
      2. console.log("Connection open.");
      3. ws.send('hello');
      4. });

      5.4 webSocket.onclose

      实例对象的onclose属性用于指定关闭连接之后的回调函数:
      1. // 在客户端与服务端建立关闭后触发
      2. ws.onclose = function(evt) {
      3. console.log("Connection closed.");
      4. };
      如果需要指定多个回调函数,可以使用addEventListener方法:
      1. ws.addEventListener("close", function(event) {
      2. console.log("Connection closed.");
      3. });

      5.5 webSocket.onmessage

      实例对象的onmessage属性用于指定接收到服务器数据后的回调函数:
      1. ws.onmessage = function(res) {
      2. console.log(res); // 打印的是MessageEvent对象
      3. console.log(res.data); // 打印的是收到的消息
      4. };
      如果需要指定多个回调函数,可以使用addEventListener方法:
      1. ws.addEventListener("message", function(res) {
      2. console.log(res); // 打印的是MessageEvent对象
      3. console.log(res.data); // 打印的是收到的消息
      4. });
      注意,服务器数据可能是二进制数据,也可能是文本,我们需要对数据进行类型的判断:
      1. ws.onmessage = function(event){
      2. if(typeof event.data === String) {
      3. console.log("文本");
      4. }
      5. if(event.data instanceof ArrayBuffer){
      6. var buffer = event.data;
      7. console.log("二进制");
      8. }
      9. }

      5.5 webSocket.send()

      实例对象的send()方法用于向服务器发送数据:
      1. ws.send('hello');

      5.7 webSocket.bufferedAmount

      实例对象的bufferedAmount属性,表示还有多少字节的二进制数据没有发送出去。它可以用来判断发送是否结束:
      1. var data = new ArrayBuffer(10000000);
      2. socket.send(data);
      3. if (socket.bufferedAmount === 0) {
      4. // 发送完毕
      5. } else {
      6. // 未发送完
      7. }

      5.8 webSocket.onerror

      实例对象的onerror属性用于指定报错时的回调函数:
      1. socket.onerror = function(event) {
      2. // handle error event
      3. };
      如果需要指定多个回调函数,可以使用addEventListener方法:
      1. socket.addEventListener("error", function(event) {
      2. // error event
      3. });

    上面总共提到了四种及时通信的协议,从性能的角度来看:WebSocket > 长连接(SEE) > 长轮询 > 短轮询但是,我们如果考虑浏览器的兼容性问题,顺序就恰恰相反了:短轮询 > 长轮询 > 长连接(SEE) > WebSocket所以,还是要根据具体的使用场景来判断使用哪种方式。

    以太坊cppgolang区别 编程

    以太坊cppgolang区别

    以太坊是一种去中心化的开源平台,它采用智能合约技术,旨在构建和运行不受干扰的分布式应用程序。作为目前最受欢迎的区块链平台之一,以太坊提供了多种编程语言的支持,其
    progolang 编程

    progolang

    Go语言(Golang)是由Google开发的一门静态类型编程语言。作为一名专业的Golang开发者,我深知这门语言的优势和特点。在本文中,我将介绍Golang
    golangn个发送者 编程

    golangn个发送者

    Golang是一种开源的编程语言,由Google团队开发,旨在提高程序的并发性和简化软件开发过程。在Go语言中,有时需要向多个接收者发送信息。本文将介绍如何在G
    golang技能图谱 编程

    golang技能图谱

    从互联网行业的快速发展到人工智能技术的日益成熟,各种编程语言也应运而生。而在这众多的编程语言中,Golang(即Go)作为一门强大且高效的开发语言备受关注。Go
    评论:0   参与:  5