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 长轮询生命周期如下:

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

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

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 objectconst 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 ProtocolsConnection: UpgradeSec-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 (      
        Practical Intro To WebSockets.      
    );  }}export default App;

登录后复制

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

HTTP GET ws://127.0.0.1:8000/ 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: vISxbQhM64Vzcr/CD7WHnw==Origin: http://localhost:3000Sec-WebSocket-Version: 13

登录后复制

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

议程2:实时信息传输

2.gif

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

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

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

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

在客户端发送和接收消息

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

/* When a user joins, I notify theserver 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 thecurrent 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));    }  });

登录后复制

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

4.gif

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

在这种情况下,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中如何进行实时通信?的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2635245.html

(0)
上一篇 2025年3月7日 04:41:24
下一篇 2025年1月4日 01:34:46

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 使用Node.js+Chrome+Puppeteer实现网站的爬取

    视频教程推荐:nodejs 教程 我们将学到什么? 在本教程中,您将学习如何使用 JavaScript 自动化和清理 web 。要做到这一点,我们将使用 Puppeteer 。Puppeteer是一个允许我们控制无头Chrome 的 Nod…

    2025年3月7日 编程技术
    200
  • react中npm是什么

    react中npm通常称为node包管理器,是Nodejs默认的、以JavaScript编写的软件包管理系统,通过npm可以安装、共享、分发代码,管理项目依赖关系。 react中的npm指的是NPM(node package manager…

    2025年3月7日
    200
  • 开发react用什么工具?

    react可以用的开发工具有:1、Chrome React Dev Tools;2、React Sight;3、React Bootstrap;4、Create React App;5、React Styleguideist等等。 适用于所…

    2025年3月7日 编程技术
    200
  • webstrom 怎么创建react项目

    webstrom创建react项目的方法:首先安装webstorm和react.js;然后打开软件界面,在顶部导航栏,依次点击“File”-“New Project”-“React APP”;最后填写“项目工程名”等相关信息即可。 本教程操…

    2025年3月7日 编程技术
    200
  • react全家桶都有什么

    react全家桶都有:1、react是核心;2、redux相当于数据库;3、React Router是专为React设计的路由解决方案;4、axios用于浏览器和Node js的http客户端;5、Ant Degisn很好的React库。 …

    2025年3月7日
    200
  • 如何在react框架中引入webpack

    在react框架中引入webpack的方法:首先创建一个文件夹;然后创建一个“package.json”的工程文件;接着全局安装webpack;最后通过“npm install”在项目中安装webpack即可。 本教程操作环境:window…

    2025年3月7日
    200
  • Node.js设置允许跨域的方法

    nodejs如何设置允许跨域?下面本篇文章就来给大家介绍一下设置方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 相关推荐:《nodejs视频教程》 设置允许所有域名跨域: app.all(“*”,function(r…

    2025年3月7日
    200
  • node.js创建简单聊天室的方法介绍

    使用nodejs如何创建一个简单聊天室?下面本篇文章给大家介绍一下。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 相关推荐:《nodejs视频教程》 刚刚开始学js,本文是基于node.js和websocket实现一个简…

    2025年3月7日 编程技术
    200
  • vue node 是什么

    vue是一套用于构建用户界面的渐进式JavaScript框架,vue采用自底向上增量开发的设计;而node是基于谷歌Chrome的JavaScript引擎构建的服务器端平台,是一个开源的跨平台运行时环境,用于开发服务器端和网络应用程序。 本…

    2025年3月7日
    200
  • win怎样升级react native 和node.js

    win升级react native和node.js的方法:1、下载最新版本的nodejs,然后进行覆盖安装;2、升级react-native脚手架,然后升级项目的react-native即可。 本文操作环境:windows7系统、react…

    2025年3月7日
    200

发表回复

登录后才能评论