0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

深入地研究WebRTC!Websocket服务器JscodeReact前端编码器

LiveVideoStack 来源:LiveVideoStack 2020-09-22 09:58 次阅读

我的动机 我们的目标是制作一个精简易用的点对点文件共享网络应用程序,将更多的精力投入到用户体验与简单地办事上。这个网络应用程序不只是针对特定的个人群体服务的,而是针对整个社区服务。 既然有这么多文件共享网站,为什么我们还要做这些呢? 当然,我也思考过这个问题,但所有的这些网站都没有真正地说明过这些文件在哪里共享或存储。这可能是一种隐私威胁,因为在当前疫情的情况下,许多人或许经常使用这些服务来共享文件甚至机密文件。使用安全的点对点连接和它的数据通道可以传输大量的文件,却不需要存储在任何服务器上,这使得它真正地结实与私有,因为只有连接的客户端/对等端直接与中间服务器通信,不需要中间服务器进行传输。 WebRTC使对等连接和数据通道成为可能。WebRTC基本上是一种相互通信与传送数据的全球网络方式,类似于蓝牙NFC和WIFI数据共享。我们可以使用WebRTC实现跨平台支持,因为它是基于网络的。 让我们更深入地研究WebRTC。 WebRTC

“WebRTC是一个免费的开放项目,通过简单的APIs为浏览器与移动应用程序提供实时通信(RTC)功能。WebRTC组件已经进行了优化,以更好地满足这一目的。” webrtc.org

好吧,假设,一个“点对点”关联考虑两部设备之间发送的直接信息,而不需要服务器保存这些信息。听起来这对我们的情况很理想对吧?不幸的是,这不是WebRTC工作的方式!

图为使用WebRTC进行数据传输 尽管WebRTC实现了点对点连接,但它确实需要一个称为信令服务器的服务器,该服务器用于共享有关预期将其相互连接的设备的数据。这些微妙之处可以通过任何传统的信息共享技术来共享。WebSockets在这里受到青睐,因为它减少了在一个庞大的建立关联的系统中共享这些额外数据的惰性。 简而言之,信令服务器帮助建立连接,然而,当连接建立后,服务器将不再涉及相关设备之间共享的信息。 一年前,当我开始我的第一个WebRTC项目时,很难找到一个在“production”级别下工作得像样的模型。后来我在网上找到了这个Youtube频道编码。开发人员给出了关于可用于生产的WebRTC应用程序的一些很好的例子。 WebRTC如何创建一个连接(技术) 好吧,没有简单的方法来解释这一点,但我的看法是,在网络上所有数量可观的设备中,无论如何都必须有一个设备通过产生信号来启动连接,并将其发送到信令服务器上。这个对等点被称为启动器,在simple-peer(此项目中使用的模块)中,当创建一个启动器对等点时,{initiator:true}会被传递给制作者/构造函数。

如图:信号服务器在运行 当我们得到对等点的信号信息时,这些信息应该通过某种方式通过信令服务器发送到不同的集线器。不同的集线器获取此信息并尝试与发起程序建立关联。在这个过程中,这些对等体同样产生它们的信号信息并被发送给发起方。发起方获取此信息并尝试与其余对等方建立连接。 瞧!这些设备现在已经连接起来,现在有一个数据通道,可以在没有中间服务器的情况下共享信息。 尽量不要过分强调你无法理解WebRTC的上述工作方式以及简单对等点如何把它抽象化。当我一开始摆弄WebRTC时,它吓了我一大跳。接下来的部分将对这一点进行更简单和细致的解释。 与WebRTC共享文件(使用simple-peer)

const express = require("express"); const http = require("http"); const app = express(); const server = http.createServer(app); const socket = require("socket.io"); const io = socket(server); const users = {}; const socketToRoom = {}; io.on('connection', socket => { socket.on("join room", roomID => { if (users[roomID]) { const length = users[roomID].length; if (length === 2) { socket.emit("room full"); return; } users[roomID].push(socket.id); } else { users[roomID] = [socket.id]; } socketToRoom[socket.id] = roomID; const usersInThisRoom = users[roomID].filter(id => id !== socket.id); socket.emit("all users", usersInThisRoom); }); socket.on("sending signal", payload => { io.to(payload.userToSignal).emit('user joined', { signal: payload.signal, callerID: payload.callerID }); }); socket.on("returning signal", payload => { io.to(payload.callerID).emit('receiving returned signal', { signal: payload.signal, id: socket.id }); }); socket.on('disconnect', () => { const roomID = socketToRoom[socket.id]; let room = users[roomID]; if (room) { room = room.filter(id => id !== socket.id); users[roomID] = room; socket.broadcast.emit('user left', socket.id); } }); }); server.listen(process.env.PORT || 8000, () => console.log('server is running on port 8000')); Websocket服务器JscodeReact前端编码器

import React, { useEffect, useRef, useState } from "react";import io from "socket.io-client";import Peer from "simple-peer";import styled from "styled-components";import streamSaver from "streamsaver"; const Container = styled.div` padding: 20px; display: flex; height: 100vh; width: 90%; margin: auto; flex-wrap: wrap;`; const worker = new Worker("../worker.js"); const Room = (props) => { const [connectionEstablished, setConnection] = useState(false); const [file, setFile] = useState(); const [gotFile, setGotFile] = useState(false); const chunksRef = useRef([]); const socketRef = useRef(); const peersRef = useRef([]); const peerRef = useRef(); const fileNameRef = useRef(""); const roomID = props.match.params.roomID; useEffect(() => { socketRef.current = io.connect("/"); socketRef.current.emit("join room", roomID); socketRef.current.on("all users", users => { peerRef.current = createPeer(users[0], socketRef.current.id); }); socketRef.current.on("user joined", payload => { peerRef.current = addPeer(payload.signal, payload.callerID); }); socketRef.current.on("receiving returned signal", payload => { peerRef.current.signal(payload.signal); setConnection(true); }); socketRef.current.on("room full", () => { alert("room is full"); }) }, []); function createPeer(userToSignal, callerID) { const peer = new Peer({ initiator: true, trickle: false, }); peer.on("signal", signal => { socketRef.current.emit("sending signal", { userToSignal, callerID, signal }); }); peer.on("data", handleReceivingData); return peer; } function addPeer(incomingSignal, callerID) { const peer = new Peer({ initiator: false, trickle: false, }); peer.on("signal", signal => { socketRef.current.emit("returning signal", { signal, callerID }); }); peer.on("data", handleReceivingData); peer.signal(incomingSignal); setConnection(true); return peer; } function handleReceivingData(data) { if (data.toString().includes("done")) { setGotFile(true); const parsed = JSON.parse(data); fileNameRef.current = parsed.fileName; } else { worker.postMessage(data); } } function download() { setGotFile(false); worker.postMessage("download"); worker.addEventListener("message", event => { const stream = event.data.stream(); const fileStream = streamSaver.createWriteStream(fileNameRef.current); stream.pipeTo(fileStream); }) } function selectFile(e) { setFile(e.target.files[0]); } function sendFile() { const peer = peerRef.current; const stream = file.stream(); const reader = stream.getReader(); reader.read().then(obj => { handlereading(obj.done, obj.value); }); function handlereading(done, value) { if (done) { peer.write(JSON.stringify({ done: true, fileName: file.name })); return; } peer.write(value); reader.read().then(obj => { handlereading(obj.done, obj.value); }) } } let body; if (connectionEstablished) { body = (

); } else { body = (

Once you have a peer connection, you will be able to share files

); } let downloadPrompt; if (gotFile) { downloadPrompt = (
You have received a file. Would you like to download the file?
); } return ( {body} {downloadPrompt} );}; export default Room; 在此Repo上找到整个代码。如果你在浏览器中尝试应用上述代码并选择一些图片文件(最好小于100KB),它会立即下载这些图片文件。这是因为这个对等点位于一个类似的浏览器中,而发送方处于提示状态。 传送和获取的信息的大小是相等的。这表明我们可以选择一次性移动整个记录! 为什么使用数据缓冲区而不是blob? 在我们过去的代码中,如果我们选择了一个巨大的文件(大于100KB),那么文档很可能不会被发送,这是WebRTC通道的某些约束的直接结果。

如图:数组缓冲区漫画插图(mozilla.org) 每个数组缓冲区一次只能有16KB的限制。简而言之,这意味着我们必须将文档划分成小数组缓冲区。 小文件可以通过WebRTC一次性发处,然而,对于大文档,明智的做法是将文件隔离到较小的数组缓冲区中,并同样发送每个部分。ArrayBuffer和Blob对象都有削减容量,这使得此过程更加简单。为此,如果你仔细查看代码,你会发现我们使用了一个名为stream saver的模块,它可以将数组缓冲区转换回blob。 笔记 因为javascript是单线程的。处理大量数组缓冲区可能导致漂亮的UI无法响应。为了解决这个问题,我们将使用服务工作人员。一个服务工作人员是浏览器在后台运行的脚本,是与Web页面分离的,这为不需要Web页面或用户交互的特性打开大门。

let array = [];self.addEventListener("message", event => { if (event.data === "download") { const blob = new Blob(array); self.postMessage(blob); array = []; } else if (event.data === "abort") { array = []; } else { array.push(event.data); }}) 在服务工作程序中处理数组缓冲区 将文件划分为数组缓冲区的优点 虽然它可能会感觉分隔文件只是一些额外的代码,并且会让东西相互纠缠,但我们得到以下好处,并且可以帮助改进我们的文档共享应用程序。

跨平台支持(由mozilla.org提供说明)

支持几乎所有的浏览器

支持庞大的文档大小——正如前面提到的,这是我们为什么要实现它的基本解释。

一个更好的方法来破译所发送信息的度量——通过在缓冲区中发送一个记录,我们现在可以显示信息,例如,发送的文档的级别,发送记录的速度等等。

识别未完成发送的文件——在无法完全发送文件的情况下,现在能够以不同的方式获取和处理文件。

结论 由于我们有一个使用WebRTC的文档直接共享程序,而且它还利用了ArrayBuffer,我们现在应该开始考虑为应用程序的生产做准备的东西了。这些细节需要更多的探索,而不仅仅是遵循一个直接的教程。 可以补充的更多内容:

信令服务器(STUN和TURN服务器)。

使多个对等连接可拓展。

当WebRTC不能工作时才用的一种混合共享方式。

提高传输效率和速度。

我希望我已经提供了足够的信息让你们开始使用WebRTC应用程序。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编码器
    +关注

    关注

    45

    文章

    3585

    浏览量

    134131
  • 服务器
    +关注

    关注

    12

    文章

    9016

    浏览量

    85171
  • WebRTC
    +关注

    关注

    0

    文章

    56

    浏览量

    11212

原文标题:使用Webrtc和React Js在网络上共享跨平台的点对点文件

文章出处:【微信号:livevideostack,微信公众号:LiveVideoStack】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    编码器种类大观:探索技术前沿与应用创新

    ,再到集成了智能算法的智能编码器,每一种编码器都在其特定领域内发挥着不可替代的作用。本文将带您深入探索编码器的多样世界,揭示其技术奥秘与应用创新。 旋转
    的头像 发表于 11-21 08:49 105次阅读

    编码器类型详解:探索不同编码技术的奥秘

    和反馈。然而,编码器并非一种单一的技术,而是涵盖了多种类型,每种类型都有其独特的工作原理和应用场景。本文将带您深入了解几种常见的编码器类型,探索它们背后的技术奥秘。 光学编码器 光学
    的头像 发表于 11-19 08:58 124次阅读
    <b class='flag-5'>编码器</b>类型详解:探索不同<b class='flag-5'>编码</b>技术的奥秘

    增量编码器与绝对值编码器的区别

    增量编码器与绝对值编码器的区别:增量编码器与绝对值编码器在精度特点对比 增量编码器的精度取决于脉冲的数量和测量的细分程度,通常情况下,其精度
    的头像 发表于 11-18 16:38 179次阅读
    增量<b class='flag-5'>编码器</b>与绝对值<b class='flag-5'>编码器</b>的区别

    二进制编码器与绝对编码器的区别

    编码器是工业自动化和机器人技术中不可或缺的组件,用于将机械位置或运动转换为电信号。二进制编码器和绝对编码器是两种常见的编码器类型,它们各自有着独特的特点和应用场景。 二进制
    的头像 发表于 11-06 09:54 312次阅读

    磁电式编码器好还是光电式编码器

    够提供非常准确的位置反馈。这使得它在需要高精度和分辨率的应用中表现尤为出色。 技术成熟 :光电式编码器在市场上已经存在多年,技术相对成熟,应用广泛。因此,用户更容易找到适合其应用需求的产品,并且技术支持和售后服务
    的头像 发表于 10-12 10:01 306次阅读

    磁电编码器和光电编码器的区别

    磁电编码器和光电编码器是两种不同类型的编码器,它们在原理、结构、性能和应用领域上都有所不同。 磁电编码器和光电编码器的区别 1. 引言
    的头像 发表于 10-12 09:54 666次阅读

    请问websocket库怎么读取服务器发来的数据?

    官方websocket库怎么读取服务器发来的数据?
    发表于 06-25 06:40

    编码器的种类及其特点

    编码器是一种将模拟信号或物理量转换为数字信号的设备,广泛应用于自动化、测量、控制等多个领域。编码器种类繁多,每种编码器都有其独特的特点和应用场景。本文将对常见的编码器种类及其特点进行详
    的头像 发表于 06-13 14:50 731次阅读

    增量编码器和绝对值编码器的区别

    在工业自动化和精密测量领域,编码器是不可或缺的关键设备。编码器能够将机械位移转换为电信号,以便于计算机或其他数字系统进行处理。在编码器的众多类型中,增量编码器和绝对值
    的头像 发表于 06-03 15:40 2546次阅读

    旋转编码器的常见类型

    详细介绍旋转编码器的常见类型,包括增量式编码器和绝对式编码器两大类,并对它们的特点、工作原理、应用场合等进行深入探讨。
    的头像 发表于 05-29 15:59 829次阅读

    编码器分辨率是什么意思 编码器分辨率和脉冲数的关系

    按照编码器支持的分辨率可以把编码器分成标清编码器、高清编码器、全高清编码器,分辨率越高帧率越高视频就越清楚。 1.
    的头像 发表于 02-21 18:07 3917次阅读
    <b class='flag-5'>编码器</b>分辨率是什么意思 <b class='flag-5'>编码器</b>分辨率和脉冲数的关系

    恒讯科技带大家深入理解:WebSocket服务器的工作原理

    WebSocket是一种在单个TCP连接上进行全双工通信的通信协议。它的设计目标是在Web浏览服务器之间提供低延迟、高效的双向通信。下面是深入理解
    的头像 发表于 01-29 16:48 443次阅读

    编码器好坏怎么判断,编码器原理

    编码器(Encoder)是将输入数据转化为特定编码表示的一种技术。对于不同类型的编码器,评判其好坏可以从多个方面进行考量,包括编码质量、速度、模型结构等。
    的头像 发表于 01-23 10:58 1799次阅读

    磁性编码器和光电编码器的比较

    伺服电机编码器是一种关键的反馈装置,用于测量和控制电机的转速和位置。在选择伺服电机编码器时,常常面临一个选择:使用磁电编码器还是光电编码器。接下来将从几个关键方面比较这两种类型的
    的头像 发表于 01-18 10:29 2961次阅读

    编码器与PLC的接线方法

    编码器分为旋转编码器和线性编码器两种。旋转编码器用于检测旋转位置和速度,而线性编码器用于检测直线位置和速度。
    发表于 12-22 09:20 1352次阅读
    <b class='flag-5'>编码器</b>与PLC的接线方法