最新公告
  • 欢迎您访问爱上源码网,分享精品整站源码,网站模板,游戏源码,APP小程序源码以及视频教程免费下载;服务永无止境!立即加入我们
  • Node和React中如何进行实时通信?

    爱上源码网文章Node和React中如何进行实时通信?的内容插图

    教程推荐:node js教程、React教程、WebSocket教程

    Web 为了支持客户端和服务器之间的全双工(或双向)通信已经走过了很长的路。这是 WebSocket 协议的主要目的:通过单个 TCP 套接字连接在客户端和服务器之间提供持久的实时通信。

    WebSocket 协议只有两个议程:1)打开握手,2)帮助数据传输。一旦服务器和客户端握手成功,他们就可以随意地以较少的开销相互发送数据。

    WebSocket 通信使用WS(端口80)或WSS(端口443)协议在单个 TCP 套接字上进行。根据 Can I Use,撰写本文时除了 Opera Mini 之外几乎所有的浏览器支持 WebSockets 。

    现状

    从历史上看,创建需要实时数据通讯(如游戏或聊天应用程序)的 Web 应用需要滥用 HTTP 协议来建立双向数据传输。尽管有许多种方法用于实现实时功能,但没有一种方法与 WebSockets 一样高效。 HTTP 轮询、HTTP流、Comet、SSE —— 它们都有自己的缺点。

    HTTP 轮询

    解决问题的第一个尝试是定期轮询服务器。 HTTP 长轮询生命周期如下:

    1. 客户端发出请求并一直等待响应。
    2. 服务器推迟响应,直到发生更改、更新或超时。请求保持“挂起”,直到服务器有东西返回客户端。
    3. 当服务器端有一些更改或更新时,它会将响应发送回客户端。
    4. 客户端发送新的长轮询请求以侦听下一组更改。

    长轮询中存在很多漏洞 —— 标头开销、延迟、超时、缓存等等。

    HTTP 流式传输

    这种机制减少了网络延迟的痛苦,因为初始请求无限期地保持打开状态。即使在服务器推送数据之后,请求也永远不会终止。 HTTP 流中的前三步生命周期方法与 HTTP 轮询是相同的。

    但是,当响应被发送回客户端时,请求永远不会终止,服务器保持连接打开状态,并在发生更改时发送新的更新。

    服务器发送事件(SSE)

    使用 SSE,服务器将数据推送到客户端。聊天或游戏应用不能完全依赖 SSE。 SSE 的完美用例是类似 Facebook 的新闻 Feed:每当有新帖发布时,服务器会将它们推送到时间线。 SSE 通过传统 HTTP 发送,并且对打开的连接数有限制。

    这些方法不仅效率低下,维护它们的代码也使开发人员感到厌倦。

    WebSocket

    WebSockets 旨在取代现有的双向通信技术。当涉及全双工实时通信时,上述现有方法既不可靠也不高效。

    WebSockets 类似于 SSE,但在将消息从客户端传回服务器方面也很优秀。由于数据是通过单个 TCP 套接字连接提供的,因此连接限制不再是问题。

    实战教程

    正如介绍中所提到的,WebSocket 协议只有两个议程。让我们看看 WebSockets 如何实现这些议程。为此我将分析一个 Node.js 服务器并将其连接到使用 React.js 构建的客户端上。

    议程1:WebSocket在服务器和客户端之间建立握手

    在服务器级别创建握手

    我们可以用单个端口来分别提供 HTTP 服务和 WebSocket 服务。下面的代码显示了一个简单的 HTTP 服务器的创建过程。一旦创建,我们会将 WebSocket 服务器绑定到 HTTP 端口:

    const webSocketsServerPort = 8000;
    const webSocketServer = require('websocket').server;
    const http = require('http');
    // Spinning the http server and the websocket server.
    const server = http.createServer();
    server.listen(webSocketsServerPort);
    const wsServer = new webSocketServer({
      httpServer: server
    });

    创建 WebSocket 服务器后,我们需要在接收来自客户端的请求时接受握手。我将所有连接的客户端作为对象保存在代码中,并在收请从浏览器发来的求时使用唯一的用户ID。

    // I'm maintaining all active connections in this object
    const clients = {};
    
    // This code generates unique userid for everyuser.
    const getUniqueID = () => {
      const s4 = () => Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
      return s4() + s4() + '-' + s4();
    };
    
    wsServer.on('request', function(request) {
      var userID = getUniqueID();
      console.log((new Date()) + ' Recieved a new connection from origin ' + request.origin + '.');
      // You can rewrite this part of the code to accept only the requests from allowed origin
      const connection = request.accept(null, request.origin);
      clients[userID] = connection;
      console.log('connected: ' + userID + ' in ' + Object.getOwnPropertyNames(clients))
    });

    那么,当接受连接时会发生什么?

    在发送常规 HTTP 请求以建立连接时,在请求头中,客户端发送 *Sec-WebSocket-Key*。服务器对此值进行编码和散列,并添加预定义的 GUID。它回应了服务器发送的握手中 *Sec-WebSocket-Accept*中生成的值。

    一旦请求在服务器中被接受(在必要验证之后),就完成了握手,其状态代码为 101。如果在浏览器中看到除状态码 101 之外的任何内容,则意味着 WebSocket 升级失败,并且将遵循正常的 HTTP 语义。

    *Sec-WebSocket-Accept* 头字段指示服务器是否愿意接受连接。此外如果响应缺少 *Upgrade* 头字段,或者 *Upgrade* 不等于 websocket,则表示 WebSocket 连接失败。

    成功的服务器握手如下所示:

    HTTP GET ws://127.0.0.1:8000/ 101 Switching Protocols
    Connection: Upgrade
    Sec-WebSocket-Accept: Nn/XHq0wK1oO5RTtriEWwR4F7Zw=
    Upgrade: websocket

    在客户端级别创建握手

    在客户端,我使用与服务器中的相同 WebSocket 包来建立与服务器的连接(Web IDL 中的 WebSocket API 正在由W3C 进行标准化)。一旦服务器接受请求,我们将会在浏览器控制台上看到 WebSocket Client Connected

    这是创建与服务器的连接的初始脚手架:

    import React, { Component } from 'react';
    import { w3cwebsocket as W3CWebSocket } from "websocket";
    
    const client = new W3CWebSocket('ws://127.0.0.1:8000');
    
    class App extends Component {
      componentWillMount() {
        client.onopen = () => {
          console.log('WebSocket Client Connected');
        };
        client.onmessage = (message) => {
          console.log(message);
        };
      }
      
      render() {
        return (
          <div>
            Practical Intro To WebSockets.
          </div>
        );
      }
    }
    
    export default App;

    客户端发送以下标头来建立握手:

    HTTP GET ws://127.0.0.1:8000/ 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: vISxbQhM64Vzcr/CD7WHnw==
    Origin: http://localhost:3000
    Sec-WebSocket-Version: 13

    现在客户端和服务器通过相互握手进行了连接,WebSocket 连接可以在接收消息时传输消息,从而实现 WebSocket 协议的第二个议程。

    议程2:实时信息传输

    爱上源码网文章Node和React中如何进行实时通信?的内容插图1

    我将编写一个基本的实时文档编辑器,用户可以将它们连接在一起并编辑文档。我跟踪了两个事件:

    1. 用户活动:每次用户加入或离开时,我都会将消息广播给所有连接其他的客户端。
    2. 内容更改:每次修改编辑器中的内容时,都会向所有连接的其他客户端广播。

    该协议允许我们用二进制数据或 UTF-8 发送和接收消息(注意:传输和转换 UTF-8 的开销较小)。

    只要我们对套接字事件onopenoncloseonmessage有了充分的了解,理解和实现 WebSockets 就非常简单。客户端和服务器端的术语相同。

    在客户端发送和接收消息

    在客户端,当新用户加入或内容更改时,我们用 client.send 向服务器发消息,以将新信息提供给服务器。

    /* When a user joins, I notify the
    server that a new user has joined to edit the document. */
    logInUser = () => {
      const username = this.username.value;
      if (username.trim()) {
        const data = {
          username
        };
        this.setState({
          ...data
        }, () => {
          client.send(JSON.stringify({
            ...data,
            type: "userevent"
          }));
        });
      }
    }
    
    /* When content changes, we send the
    current content of the editor to the server. */
    onEditorStateChange = (text) => {
     client.send(JSON.stringify({
       type: "contentchange",
       username: this.state.username,
       content: text
     }));
    };

    我们跟踪的事件是:用户加入和内容更改。

    从服务器接收消息非常简单:

    componentWillMount() {
      client.onopen = () => {
       console.log('WebSocket Client Connected');
      };
      client.onmessage = (message) => {
        const dataFromServer = JSON.parse(message.data);
        const stateToChange = {};
        if (dataFromServer.type === "userevent") {
          stateToChange.currentUsers = Object.values(dataFromServer.data.users);
        } else if (dataFromServer.type === "contentchange") {
          stateToChange.text = dataFromServer.data.editorContent || contentDefaultMessage;
        }
        stateToChange.userActivity = dataFromServer.data.userActivity;
        this.setState({
          ...stateToChange
        });
      };
    }

    在服务器端发送和侦听消息

    在服务器中,我们只需捕获传入的消息并将其广播到连接到 WebSocket 的所有客户端。这是臭名昭着的 Socket.IO 和 WebSocket 之间的差异之一:当我们使用 WebSockets 时,我们需要手动将消息发送给所有客户端。 Socket.IO 是一个成熟的库,所以它自己来处理。

    const sendMessage = (json) => {
      // We are sending the current data to all connected clients
      Object.keys(clients).map((client) => {
        clients[client].sendUTF(json);
      });
    }
    
    connection.on('message', function(message) {
        if (message.type === 'utf8') {
          const dataFromClient = JSON.parse(message.utf8Data);
          const json = { type: dataFromClient.type };
          if (dataFromClient.type === typesDef.USER_EVENT) {
            users[userID] = dataFromClient;
            userActivity.push(`${dataFromClient.username} joined to edit the document`);
            json.data = { users, userActivity };
          } else if (dataFromClient.type === typesDef.CONTENT_CHANGE) {
            editorContent = dataFromClient.content;
            json.data = { editorContent, userActivity };
          }
          sendMessage(JSON.stringify(json));
        }
      });

    将消息广播到所有连接的客户端。

    爱上源码网文章Node和React中如何进行实时通信?的内容插图2

    浏览器关闭后会发生什么?

    在这种情况下,WebSocket调用 close 事件,它允许我们编写终止当前用户连接的逻辑。在我的代码中,当用户离开文档时,会向其余用户广播消息:

    connection.on('close', function(connection) {
        console.log((new Date()) + " Peer " + userID + " disconnected.");
        const json = { type: typesDef.USER_EVENT };
        userActivity.push(`${users[userID].username} left the document`);
        json.data = { users, userActivity };
        delete clients[userID];
        delete users[userID];
        sendMessage(JSON.stringify(json));
      });

    该应用程序的源代码位于GitHub上的 repo 中。

    结论

    WebSockets 是在应用中实现实时功能的最有趣和最方便的方法之一。它为我们提供了能够充分利用全双工通信的灵活性。我强烈建议在尝试使用 Socket.IO 和其他可用库之前先试试 WebSockets。

    编码快乐!

    更多编程相关知识,请访问:编程教学!!

    以上就是Node和React中如何进行实时通信?的详细内容,更多请关注爱上源码网其它相关文章!

  • 微信
  • 分享
  • 相关标签:Node React WebSocket
  • 本文转载于:segmentfault,如有侵犯,请联系916990011@qq.com删除
    • 上一篇:爬虫分析之 JS逆向某验滑动加密(1)
    • 下一篇:nodejs接口如何传输数据?

    相关文章

    相关视频

    • 一些关于React的常见面试题(分享)
    • 2020年前端React面试题大汇总(收藏)
    • 用Node.js如何快速构建一个API服务器?
    • 深入解析 Node.js 的回调队列
    • Deno中如何使用 Node 模块?
    • 深入浅析Node.js的模块加载机制
    • 为你的Node应用程序选择最佳的JS引擎
    • Linux环境下如何更新node版本(升级)
    • nodejs版的orm库–sequelize
    • Mac和Windows下如何使用nvm安装和管理多…
    • Node和React中如何进行实时通信?
    • React Native初体验及其它环境搭建
    • React Native项目目录结构详解
    • 初识ReactJS
    • Nodejs web服务
    • Node.js 自定义模块

    本文有爱上源码下载完入驻作者发布,如果对您版权造成侵害,可以联系本站站长管理进行维权删除,本站收到维权24小时内进行处理,谢谢您关注23ym.cn!
    本站分享大量程序员技术文章以及对编程开发的初级入门教程,包括图文讲解笔记和高清视频下载~

    重要声明:
    1.本站视频教程,软件及网站源码版权均属于原作者所有,您必须在下载后的24个小时之内,从您的电脑中删除!非法商业用途,后果自负!
    2.本站不保证所提供下载资源的安全性和完整性,仅供下载学习之用!如链接失效或资源含外站广告,请联系客服处理!给予奖励!
    3.本站所有资源来源于用户上传和网络,因此不包含技术服务请大家谅解!本站提供有偿服务!如有侵权请联系在线客服!
    4.如您手中有优质资源或教程,可以自助投稿发布,成功分享后有奖励和额外收入!
    5.如您需要正版微擎模块可联系本站客服,我们有价值30w+商业微擎应用出售微擎坑位和招收代理!
    6.400电话/软著/ICP,EDI许可证/商标特价办理中!
    爱上源码下载网 » Node和React中如何进行实时通信?

    常见问题FAQ

    从网站下载的源码都有安装教程么?不会安装怎么办?
    本站发布的网站源码和模板资源大部分在压缩包内都有教程,如您不会安装可以联系本站在线技术进行付费安装。
    爱上源码的所有源码都是亲测能正常运行的么?
    本站目前拥有资源10w+,包含整站源码,网站模板,游戏源码,小程序源码,视频教程,破解软件等,每天也在测试更新;因时间和精力有限我们无法对资源进行一一测试,只能保证所分享资源内容无误,希望理解。
    我手中的优质资源可以在你这换钱或者VIP么?
    爱上源码支持投稿,欢迎发布您手中的优质资源进行售卖;本站VIP支持免费获取,目前邀请10人注册爱上源码即可免费获取VIP。
    爱上源码除了资源分享还有其他业务没?
    【价值30W+微擎模块出售正版商业微擎坑位及招收代理,详情咨询本站客服!】我们团队目前运营并推广几套商业化saas智能小程序系统能满足大部分小程序开发需求,并由SaaS和独立部署版商城小程序系统;另外销售400电话,各种ICP/EDI资质证书办理,软著和商标注册服务等。

    发表评论

    • 18会员总数(位)
    • 33905资源总数(个)
    • 0本周发布(个)
    • 0 今日发布(个)
    • 290稳定运行(天)

    提供最优质的资源集合

    开通VIP 源码下载