使用WebRTC通过Web跨设备共享文件
在网络上共享文件的方法有很多种。您将文件上传到服务器并共享一个链接,其他人可以使用该链接下载该文件。虽然这是一种经过验证的共享数据的方法,现在让我们尝试用一种更“设备到设备”的共享方法来解决这个问题,而不是“设备-服务器-设备”。
思考这个问题,我不断回到蓝牙,NFC,WiFi直接共享等技术。虽然我喜欢这些技术,但老实说,它们在速度,范围和整体体验方面有点平淡无奇。
相反,Web喜欢连接到全球网络。通过实现更好的体验,我尝试将Web的好处与蓝牙的文件共享结合起来。
WebRTC
WebRTC是Web Real-Time Communication的缩写。WebRTC提供了一组API,可以实现设备到设备(点对点)连接,通过Web传输音频,视频或任何常规数据。
从理论上讲,“对等”连接允许两个设备之间的直接数据传输,而不需要服务器来持久化数据。听起来很酷对吧...但这不是WebRTC的工作方式!😕
虽然WebRTC创建了点对点连接,但它仍然需要服务器端。服务器(称为信令服务器)用于共享有关实现此连接所需的设备的信息。WebSockets在这里是首选,因为它减少了在大型网络中共享这些额外信息的延迟。
简单地说,服务器帮助建立连接,但是一旦建立连接,它就不应该再访问,设备共享的数据。
让我们尝试使用WebRTC在两个设备之间实现文件共享机制。由于WebRTC的原始API使实现连接变得繁琐,因此我将使用一个库simple-peer和download.js。
WebRTC如何创建连接
在网络中的所有设备中,至少有一个设备向信令服务器发起连接。
一们得到了一个节点的信号数据,数据通过信令服务器方式发送到其他节点。其他节点接收此数据并尝试与发起方建立连接。在此过程中,这些节点还生成信号数据发送到发起者。发起方接收此数据并尝试与其余节点建立连接。
这是个神奇的魔术......嘣.......设备连接!✨
与WebRTC共享文件
<html>
<head>
<title>Sharing files using WebRTC</title>
</head>
<body>
<input type="file" id="file-input">
<script src="https://cdn.jsdelivr.net/npm/simple-peer@9.5.0/simplepeer.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/downloadjs/1.4.8/download.min.js"></script>
<script src="file-sharing-webrtc.js"></script>
</body>
</html>
/**
* Peer 1 (Sender)
* Peer 2 (Receiver)
* This example has both the peers in the same browser window.
* In a real application, the peers would exchange their signaling data for a proper connection.
* The signaling server part is omitted for simplicity
*/
const peer1 = new SimplePeer({ initiator: true });
const peer2 = new SimplePeer();
/**
* Implementing the WebRTC connection between the nodes
*/
// Share the signalling data of sender with the receivers
peer1.on('signal', data => {
peer2.signal(data);
});
// Share the signalling data of receiver with the sender
peer2.on('signal', data => {
peer1.signal(data);
});
/**
* Connection established, now sender can send files to other peers
*/
peer1.on('connect', () => {
const input = document.getElementById('file-input');
// Event listener on the file input
input.addEventListener('change', () => {
const file = input.files[0];
console.log('Sending', file)
// We convert the file from Blob to ArrayBuffer, since some browsers don't work with blobs
file.arrayBuffer()
.then(buffer => {
// Off goes the file!
peer1.send(buffer);
});
});
});
/**
* Receiver receives the files
*/
peer2.on('data', data => {
// Convert the file back to Blob
const file = new Blob([ data ]);
console.log('Received', file);
// Download the received file using downloadjs
download(file, 'test.png');
});
现在打开devtools中的控制台,检查一些东西(如下图所示)。注意size属性。发送和接收的数据大小相同。这表明我们能够一次性传输整个文件!🎉
让我们开始分块文件📦
在我们前面的例子中,如果我们选择一个大文件(超过100 KB),该文件很可能不会被传输,这是因为WebRTC通道的一些限制。
小文件可以通过WebRTC一次性发送,但对于较大的文件,将文件分成较小的块并相应地发送,是一个好主意。
现在的问题是每个块的大小应该是多少?这没有硬性限制。每个浏览器内部对webbrtc和数据碎片的实现略有不同。新浏览器中的一些改进不适用于旧浏览器😑。从大量的搜索中,我已经假设每个块的安全最大限制是16KB。让我们将分块添加到现有代码中。
/**
* Peer 1 (Sender)
* Peer 2 (Receiver)
* This example has both the peers in the same browser window.
* In a real application, the peers would exchange their signaling data for a proper connection.
* The signaling server part is omitted for simplicity
*/
const peer1 = new SimplePeer({ initiator: true });
const peer2 = new SimplePeer();
/**
* Implementing the WebRTC connection between the nodes
*/
// Share the signalling data of sender with the receivers
peer1.on('signal', data => {
peer2.signal(data);
});
// Share the signalling data of receiver with the sender
peer2.on('signal', data => {
peer1.signal(data);
});
/**
* Connection established, now sender can send files to other peers
*/
peer1.on('connect', () => {
const input = document.getElementById('file-input');
// Event listener on the file input
input.addEventListener('change', () => {
const file = input.files[0];
console.log('Sending', file);
// We convert the file from Blob to ArrayBuffer
file.arrayBuffer()
.then(buffer => {
/**
* A chunkSize (in Bytes) is set here
* I have it set to 16KB
*/
const chunkSize = 16 * 1024;
// Keep chunking, and sending the chunks to the other peer
while(buffer.byteLength) {
const chunk = buffer.slice(0, chunkSize);
buffer = buffer.slice(chunkSize, buffer.byteLength);
// Off goes the chunk!
peer1.send(chunk);
}
// End message to signal that all chunks have been sent
peer1.send('Done!');
});
});
});
/**
* Receiver receives the files
*/
const fileChunks = [];
peer2.on('data', data => {
if (data.toString() === 'Done!') {
// Once, all the chunks are received, combine them to form a Blob
const file = new Blob(fileChunks);
console.log('Received', file);
// Download the received file using downloadjs
download(file, 'test.png');
}
else {
// Keep appending various file chunks
fileChunks.push(data);
}
});
分组的好处
虽然它可能会觉得分块只是一些额外的代码,使事情变得复杂,我们得到以下好处,可以帮助改善我们的文件共享应用。😇
- 支持大文件
- 一种更好的解释传输数据量的方法——通过以块的形式发送文件,我们现在可以显示诸如文件传输百分比、文件传输速率等数据。
- 检测不完整的文件传输——文件不能完全传输的情况,现在可以被捕获并以不同的方式处理。
接下来是什么?
现在我们已经有了一个使用WebRTC构建的简单的文件共享应用程序,它也使用了分块处理,我们现在必须开始考虑使我们的应用程序为生产做好准备的东西。我不会在这里详细介绍它们,但会给出一些关于我们如何改进应用的一般性建议。
- 信令服务器——在上面的例子中,接收方和发送方都在同一个浏览器窗口中。这在现实生活中不会发生。因此,请考虑使用信令服务器使其成为真正的设备到设备。
- 共享多个文件——根据上面的示例,可以很容易地实现多个文件的共享。
- 当WebRTC连接失败时,添加一些回退
原文: New way of sharing files across devices over the web using WebRTC | by Akash Hamirwasia | Medium
转载自:https://juejin.cn/post/7353442647766728715