使用Peer.js发送/接收视频文件数据失败问题求助
问题分析与修复方案
核心问题点
- 跨房间消息推送错误:服务端使用全局广播推送新用户加入通知,导致非目标dashboard的用户也收到连接请求。
- PeerJS入站连接未处理:仅主动发起连接但未监听其他peer的连接请求,导致接收方无法感知连接,自然收不到数据。
- 发送逻辑耦合过紧:发送按钮事件绑定在单个连接的回调中,无法向多个已连接节点发送数据,且重复绑定会引发异常。
修复后的代码
服务端代码
// Creating a express server const express = require('express'); const app = express(); const server = require('http').Server(app); const io = require('socket.io')(server); // Passing the server created to socket.io const { v4: uuidV4 } = require('uuid') // Set up Express.js app.set('view engine', 'ejs'); app.use(express.static('public')); app.get('/', (req, res) => { res.redirect(`/${uuidV4()}`) }); app.get('/:dashboard', (req, res) => { res.render('dashboard', { dashboardId: req.params.dashboard }) }) // Set up Socket.io io.on('connection', socket => { socket.on('join', (dashboardId, userId) => { socket.join(dashboardId) // 仅向当前dashboard内的其他用户推送新用户加入通知 socket.to(dashboardId).emit('userJoined', { userId: userId }) }) }) // Start the server const port = 3000; server.listen(port, () => { console.log(`Server running on port ${port}`); });
客户端代码
const socket = io('/'); const peer = new Peer(undefined, { host: '/', port: '3001' }); // 存储所有已建立的Peer连接 const activeConnections = []; const video = document.getElementById('videoPlayer'); const fileInput = document.getElementById('fileInput'); const sendButton = document.getElementById('sendButton'); const CHUNK_SIZE = 5120; // 5KB // 处理数据接收的通用逻辑 function handlePeerData(conn) { let videoData = new Uint8Array(); conn.on('data', function (data) { console.log('Received chunk ' + (data.chunkIndex + 1) + ' of ' + data.totalChunks); // 扩容数组以容纳新数据 if (videoData.length < (data.chunkIndex + 1) * CHUNK_SIZE) { const newBuffer = new Uint8Array((data.chunkIndex + 1) * CHUNK_SIZE); newBuffer.set(videoData); videoData = newBuffer; } videoData.set(data.chunk, data.chunkIndex * CHUNK_SIZE); if (data.chunkIndex + 1 === data.totalChunks) { const videoBlob = new Blob([videoData], { type: 'video/mp4' }); const videoURL = URL.createObjectURL(videoBlob); video.src = videoURL; video.play(); } }); } // 发送文件到所有已连接的Peer function sendFileToPeers(file) { const fileReader = new FileReader(); fileReader.readAsArrayBuffer(file); fileReader.onload = function (event) { const arrayBuffer = event.target.result; const totalChunks = Math.ceil(arrayBuffer.byteLength / CHUNK_SIZE); activeConnections.forEach(conn => { let offset = 0; let chunkIndex = 0; while (offset < arrayBuffer.byteLength) { const chunk = arrayBuffer.slice(offset, offset + CHUNK_SIZE); const data = { chunk, name: file.name, totalChunks, chunkIndex }; console.log('Sending chunk ' + (chunkIndex + 1) + ' of ' + totalChunks + ' to ' + conn.peer); conn.send(data); offset += CHUNK_SIZE; chunkIndex += 1; } }); }; } // 初始化Peer连接 peer.on('open', function (id) { socket.emit('join', DASHBOARD_ID, id); // 监听新用户加入,主动发起连接 socket.on('userJoined', (userData) => { console.log('User joined:', userData.userId); const conn = peer.connect(userData.userId); conn.on('open', function () { console.log('Connected to peer: ' + conn.peer); activeConnections.push(conn); handlePeerData(conn); }); }); // 监听其他Peer发起的入站连接 peer.on('connection', (conn) => { console.log('Incoming connection from: ' + conn.peer); conn.on('open', () => { activeConnections.push(conn); handlePeerData(conn); }); }); // 绑定发送按钮事件(仅绑定一次) sendButton.addEventListener('click', function () { const file = fileInput.files[0]; if (!file) return; sendFileToPeers(file); }); });
额外说明
- 新增
activeConnections数组管理所有已建立的Peer连接,支持向多个节点同时发送视频。 - 优化
videoData的扩容逻辑,避免因初始数组长度不足导致的数据截断。 - 将数据接收和发送逻辑抽离为通用函数,提升代码复用性和可维护性。
内容的提问来源于stack exchange,提问作者archie09
相关产品推荐
相关产品推荐

