WebRTC实现跨设备P2P直连传输文件秒传
·
WebRTC 跨设备文件传输解决方案
WebRTC(Web Real-Time Communication)技术不仅支持音视频通信,其 RTCDataChannel接口也非常适合实现点对点(P2P)的跨设备文件传输,具有低延迟、无需中转服务器(可直连时)等优势。

核心实现方案
1. 基础架构设计
// 文件传输核心类框架
class WebRTCFileTransfer {
constructor() {
this.peerConnection = null;
this.dataChannel = null;
this.fileChunkSize = 16 * 1024; // 16KB 每块 this.transferState = {
file: null,
offset: 0,
chunks: [],
receivedSize: 0 };
}
// 初始化 PeerConnection
async initializeConnection(configuration = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] }) {
this.peerConnection = new RTCPeerConnection(configuration);
// 监听 ICE 候选
this.peerConnection.onicecandidate = (event) => {
if (event.candidate) {
// 通过信令服务器发送候选 this.sendSignal('candidate', event.candidate);
}
};
// 监听连接状态
this.peerConnection.onconnectionstatechange = () => {
console.log('Connection state:', this.peerConnection.connectionState);
};
}
}
2. 信令服务器实现(关键)
WebRTC 需要信令服务器交换 SDP 和 ICE 候选信息。以下是简化的 WebSocket 信令服务器:
// Node.js + WebSocket 信令服务器
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
const rooms = new Map();
wss.on('connection', (ws) => {
ws.on('message', (message) => {
const data = JSON.parse(message);
switch (data.type) {
case 'join':
if (!rooms.has(data.roomId)) {
rooms.set(data.roomId, []);
}
rooms.get(data.roomId).push({ ws, id: data.userId });
break;
case 'offer':
case 'answer':
case 'candidate':
// 转发信令给房间内其他用户
const room = rooms.get(data.roomId);
if (room) {
room.forEach(client => {
if (client.id !== data.userId) {
client.ws.send(JSON.stringify(data));
}
});
}
break;
}
});
});
3. 文件分片传输实现
// 发送方:文件分片处理
async function sendFile(file) {
const chunkSize =16 * 1024; // 16KB const totalChunks = Math.ceil(file.size / chunkSize);
let offset = 0;
// 发送文件元数据 const metadata = {
type: 'metadata',
fileName: file.name,
fileSize: file.size,
fileType: file.type,
totalChunks: totalChunks };
dataChannel.send(JSON.stringify(metadata));
// 分片发送文件内容 while (offset < file.size) {
const chunk = file.slice(offset, offset + chunkSize);
const reader = new FileReader();
await new Promise((resolve) => {
reader.onload = (e) => {
const chunkData = {
type: 'chunk',
chunkIndex: Math.floor(offset / chunkSize),
data: e.target.result,
isLast: offset + chunkSize >= file.size
};
dataChannel.send(JSON.stringify(chunkData));
resolve();
};
reader.readAsArrayBuffer(chunk);
});
offset += chunkSize;
updateProgress((offset / file.size) * 100);
}
}
// 接收方:文件重组
function setupReceiver() {
let receivedChunks = [];
let fileMetadata = null;
let receivedCount = 0;
dataChannel.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.type) {
case 'metadata':
fileMetadata = data;
receivedChunks = new Array(data.totalChunks);
break;
case 'chunk':
receivedChunks[data.chunkIndex] = data.data;
receivedCount++;
if (receivedCount === fileMetadata.totalChunks) {
reassembleFile(fileMetadata, receivedChunks);
}
break;
}
};
}
function reassembleFile(metadata, chunks) {
const blob = new Blob(chunks, { type: metadata.fileType });
const url = URL.createObjectURL(blob);
// 创建下载链接 const a = document.createElement('a');
a.href = url;
a.download = metadata.fileName;
a.click();
URL.revokeObjectURL(url);
}
4. 传输优化策略
// 流量控制与重传机制
class TransferController {
constructor() {
this.windowSize = 10; // 滑动窗口大小
this.sentPackets = new Map();
this.ackQueue = [];
this.sequenceNumber = 0;
}
// 可靠传输实现
sendWithAck(data) {
const packet = {
seq: this.sequenceNumber++,
data: data,
timestamp: Date.now(),
retries: 0
};
this.sentPackets.set(packet.seq, packet);
dataChannel.send(JSON.stringify({
type: 'data',
seq: packet.seq,
payload: data }));
// 启动超时重传
setTimeout(() => this.checkAck(packet.seq), 1000);
}
// 接收方确认
sendAck(seq) {
dataChannel.send(JSON.stringify({
type: 'ack',
seq: seq
}));
}
}
完整实现对比
| 特性 | 纯 WebRTC 方案 | WebRTC + IndexedDB | WebRTC + 服务端辅助 |
|---|---|---|---|
| 传输速度 | 高(P2P直连) | 中等 | 中等(依赖中继) |
| 可靠性 | 中等(依赖NAT穿透) | 高(本地存储) | 高(服务端备份) |
| 大文件支持 | 受内存限制 | 支持超大文件 | 支持超大文件 |
| 离线传输 | 需要初始连接 | 支持断点续传 | 需要网络连接 |
| 实现复杂度 | 中等 | 较高 | 高 |
部署配置示例
# Docker 部署配置
version: '3.8'
services:
signaling:
image: node:16
ports:
- "8080:8080"
volumes:
- ./signaling-server:/app
command: node server.js
turn-server:
image: coturn/coturn ports:
"3478:3478"
- "3478:3478/udp"
- "5349:5349"
environment:
- TURN_SECRET=your-secret-key - REALM=your-domain.com
command: |
--fingerprint
--lt-cred-mech
--realm=${REALM}
--user=username:${TURN_SECRET}
--no-tls
--no-dtls
安全增强措施
// 端到端加密
async function encryptChunk(chunk, key) {
const iv = crypto.getRandomValues(new Uint8Array(12));
const algorithm = { name: 'AES-GCM', iv: iv };
const encrypted = await crypto.subtle.encrypt(
algorithm,
key,
chunk );
return {
iv: Array.from(iv),
data: Array.from(new Uint8Array(encrypted))
};
}
// 生成传输密钥
async function generateTransferKey() {
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
const exported = await crypto.subtle.exportKey('jwk', key);
return JSON.stringify(exported); // 通过安全通道共享
}
性能监控
// 传输统计
class TransferMetrics {
constructor() {
this.metrics = {
startTime: Date.now(),
bytesTransferred: 0,
chunksSent: 0,
retransmissions: 0,
latencySamples: []
};
}
logTransfer(chunkSize) {
this.metrics.bytesTransferred += chunkSize;
this.metrics.chunksSent++;
// 计算实时速度 const elapsed = (Date.now() - this.metrics.startTime) / 1000;
const speed = (this.metrics.bytesTransferred / elapsed / 1024).toFixed(2);
return {
speed: `${speed} KB/s`,
progress: `${this.metrics.bytesTransferred} bytes`,
efficiency: `${this.metrics.retransmissions / this.metrics.chunksSent * 100}% retransmission rate`
};
}
}
此方案充分利用 WebRTC 的 P2P 特性,在支持 STUN/TURN 的情况下可实现 NAT 穿透,提供高效的文件传输能力。关键优化点包括分片传输、流量控制、断点续传(结合 IndexedDB)和端到端加密。
当前最佳实现案例:SendTomo文件传输工具,跨设备互传、跨网络、不限速、支持大文件快速传输、文件不经过服务器。
更多推荐
所有评论(0)