You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Socket.io实现多客户端文件共享时陷入死循环问题求助

Socket.io多客户端文件共享死循环问题修复

问题根源

  1. 重复绑定事件监听:每次调用shareFile都会给socket新增fs-share事件监听,导致同一事件触发多次回调,引发循环。
  2. Server端事件逻辑错误:原代码中fs-start事件触发后,Server广播fs-meta事件,导致客户端陷入fs-meta→emit fs-start→Server广播fs-meta的无限循环。
  3. 无传输终止逻辑:当文件块传输完毕(chunk.length === 0)时,未移除事件监听,也未停止后续触发逻辑,死循环持续。
  4. 语法与资源错误:存在选择器引号缺失、CDN地址拼写错误(cloudfare→cloudflare)的问题。

修复后的代码

1. server.js

const express = require("express");
const app = express();
const socketio = require("socket.io");

app.use(express.static(__dirname + '/public'));

const expressServer = app.listen(3000);
const io = socketio(expressServer)

io.on('connection',(socket)=>{
  // 广播文件元数据给所有客户端
  socket.on('file-meta',function(data){
     io.emit('fs-meta',data.metadata);
  })
  // 转发接收端的下块请求给发送端
  socket.on('request-next-chunk',function(){
     io.emit('send-next-chunk');
  })
  // 广播文件块给所有客户端
  socket.on('file-raw',function(data){
     io.emit('fs-share',data.buffer);
  })
})

2. sender.html

<div class="file-input">
 <label for="file-input">Select files for sharing</label>
 <input type="file" id="file-input">
</div>

<script src="/socket.io/socket.io.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/downloadjs/1.4.1/download.min.js"></script>
<script>
 const socket = io('http://localhost:3000');
 let fileShare = {};
 // 修复选择器引号缺失问题
 document.querySelector('#file-input').addEventListener("change",function(e){
 let file = e.target.files[0];
 if(!file){
  return;
 }
 let reader = new FileReader();
 reader.onload = function(e){
  let buffer = new Uint8Array(reader.result);
  shareFile({
   filename:file.name,
   total_buffer_size:buffer.length,
   buffer_size:524288
   },buffer);
 }
 reader.readAsArrayBuffer(file);
})

// 存储当前传输的状态,避免函数参数作用域问题
let currentTransfer = {};

function shareFile(metadata,buffer){
 currentTransfer.metadata = metadata;
 currentTransfer.buffer = buffer;
 // 移除旧监听,避免重复绑定
 socket.off('send-next-chunk');
 // 绑定传输下块的监听
 socket.on('send-next-chunk', sendNextChunk);
 // 发送文件元数据
 socket.emit("file-meta",{metadata:metadata});
}

function sendNextChunk(){
 const metadata = currentTransfer.metadata;
 let buffer = currentTransfer.buffer;
 let chunk = buffer.slice(0, metadata.buffer_size);
 currentTransfer.buffer = buffer.slice(metadata.buffer_size, buffer.length);
 
 if(chunk.length !== 0){
   socket.emit("file-raw",{buffer:chunk});
 } else {
   // 传输完毕,移除监听并清空状态
   socket.off('send-next-chunk');
   currentTransfer = {};
 }
}

socket.on("fs-meta",function(metadata){
 if(Object.keys(metadata).length === 0) return; // 忽略空的元数据信号
 fileShare.metadata = metadata;
 fileShare.transmitted = 0;
 fileShare.buffer = [];
 // 请求发送第一块数据
 socket.emit("request-next-chunk");
});

socket.on("fs-share",function(buffer){
 fileShare.buffer.push(buffer);
 fileShare.transmitted += buffer.byteLength;
 if(fileShare.transmitted === fileShare.metadata.total_buffer_size){
   download(new Blob(fileShare.buffer), fileShare.metadata.filename);
   fileShare={};
 }else {
   // 请求下一块数据
   socket.emit("request-next-chunk");
 }
});
</script>

关键修复说明

  • 避免重复绑定:每次开始传输前用socket.off()移除旧的事件监听,确保同一时间只有一个回调生效。
  • 修正事件流程:将原有的fs-start拆分为request-next-chunk(接收端请求下块)和send-next-chunk(发送端响应传输),解决Server错误广播导致的循环。
  • 添加终止逻辑:当文件块传输完毕时,移除事件监听并清空传输状态,彻底终止循环。
  • 修复语法错误:修正了选择器引号缺失和CDN地址拼写问题。

内容的提问来源于stack exchange,提问作者Deepak Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 04:05:56