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应用程序。

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

    关注

    41

    文章

    3362

    浏览量

    131558
  • 服务器
    +关注

    关注

    12

    文章

    8120

    浏览量

    82534
  • WebRTC
    +关注

    关注

    0

    文章

    55

    浏览量

    11139

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

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

收藏 人收藏

    评论

    相关推荐

    鸿蒙原生应用开发-网络管理WebSocket连接

    一、场景介绍 使用WebSocket建立服务器与客户端的双向连接,需要先通过createWebSocket()方法创建WebSocket对象,然后通过connect()方法连接到服务器
    发表于 04-07 09:46

    linux服务器和windows服务器

    Linux服务器和Windows服务器是目前应用最广泛的两种服务器操作系统。两者各有优劣,也适用于不同的应用场景。本文将 对Linux服务器和Windows
    发表于 02-22 15:46

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

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

    【飞腾派4G版免费试用】如何在飞腾开发板上安装EMQX MQTT服务器

    MQTT服务器的搭建和基本测试。如果要部署生产环境下可用的MQTT服务器,还需要进行最重要的认证配置 默认情况下EMQX允许任何客户端连接,知道用户创建了认证。认证根据客户端提供的
    发表于 12-26 11:16

    宏集产品 | 增量式光纤编码器开箱介绍 #编码器 #增量式编码器 #光纤编码器 #工业控制

    编码器光纤
    虹科工业物联网技术
    发布于 :2023年12月04日 14:13:50

    websocket协议的原理

    WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。 WebSocket通信协议于201
    的头像 发表于 11-09 15:13 434次阅读
    <b class='flag-5'>websocket</b>协议的原理

    编码器和光电编码器的未来

    15年左右行业内开始掀起风磁编码器替代光电编码器,而且在22年的时候国内几家磁编发展迅速取得了很大的成绩,可是23年开始随着光电编码成本的下调技术的革新,又有客户回归到用光电的技术。 是不是现在达到一个平衡点了?还是说磁编还有突
    发表于 09-26 13:03

    编码器音频功能

    数字视频监控系统需要音频功能,音频功能包括音频输入和输出功能,输入功能是对前端的音频输入进行与视频同步的录音,输出功能指控制中心可以对前端现场进行音频广播输出。目前主流编码器具有与视频通道相当
    的头像 发表于 08-25 11:11 439次阅读

    视频编码器的软件功能组成

    视频编码器的软件功能主要包括视频的编码压缩、与客户端的连接、发送视频流给客户端、接收客户端发送来的配置及控制命令、接收前端传感器的信号状态改变并更新服务器、对登录连接的用户进行认证、提
    的头像 发表于 08-17 10:21 328次阅读
    视频<b class='flag-5'>编码器</b>的软件功能组成

    编码器 (示波器演示+拆解)

    编码器
    学习电子知识
    发布于 :2023年07月26日 21:13:51

    编码器接口程序】定义、修改编码器脉冲计数的正方向

    编码器
    白加黑
    发布于 :2023年06月20日 17:46:52

    编码器的作用

    编码器
    YS YYDS
    发布于 :2023年06月02日 23:26:50

    如何让WebSocket服务器库使用ethernet2和有线以太网连接而不是WIFI的方向?

    WebSocket 服务器库使用 ethernet2 和有线以太网连接而不是 WIFI 的方向。我试图修改 Websocket Server.h 但当然它本身包括旧的以太网库。因此,我只是问是否
    发表于 05-19 11:07

    编码器是什么?编码器有哪些分类及应用

    编码器是什么?编码器有哪些分类及应用;编码器是什么?在数字信号处理和通信系统中,编码器是一种重要的设备,用于将原始数据转换为字符序列或二进制码序列。
    的头像 发表于 05-18 11:08 3561次阅读
    <b class='flag-5'>编码器</b>是什么?<b class='flag-5'>编码器</b>有哪些分类及应用

    增量型编码器与绝对值编码器

    增量型编码器与绝对值型编码器怎么选择?在进行编码器选择时,增量型编码器和绝对值型编码器是两种常见的选择。增量型
    的头像 发表于 05-08 11:28 1506次阅读
    增量型<b class='flag-5'>编码器</b>与绝对值<b class='flag-5'>编码器</b>