问题描述
我想实现 socket.io 房间到房间的文件共享系统,以便用户可以将图像发送到他们各自的房间,所有用户都可以看到它,我尝试使用 base64 编码方法将发送图像文件发送到特定房间但它只能发送大约 700kb 到 800kb 的文件。
Is there any easier way of doing this and can support larger files above 1mb and it should be able to load images progressively?
I am using ejs template engine,nodejs,socket.io,javascript.
Console.log("please help me guys if you any idea about this,I tried many things but none of them are working and I have read the socket.io documentation but didn't get any clue about it
我也尝试过二进制流,但没有成功,请帮我提供一些代码示例
解决方法
您可能会发现客户端使用房间名称将文件上传到您的 http 服务器更容易,然后让您的 http 服务器通过 socket.io 向房间中的所有其他客户端发送消息,其中包含客户端可以使用http下载文件。 socket.io 不是流协议,它是基于数据包或消息的协议,因此要发送大数据,必须将其分解为消息,然后在客户端重新组装。这可以做到,但这只是额外的非标准工作,http 上传和下载已经知道怎么做。
以下是步骤:
- 客户端通过 http post 将文件上传到服务器,并将房间名称作为表单中的一个字段。
- 服务器接收上传的文件,为其分配一个唯一 ID 并将其存储在服务器磁盘上的临时位置。
- 当文件上传完成后,服务器通过 socket.io 通知房间中的所有其他客户端文件已上传并可供下载,并向他们发送包含 uniqueID 的下载 URL。
- 每个客户端使用他们收到的唯一 URL 通过 http 发送下载文件的请求。
- 服务器根据 http 请求将文件提供给每个客户端。
- 服务器要么跟踪所有客户端现在是否已完成下载,要么在一段时间后根据文件的时间戳(仅清理磁盘空间)使用定期计时器上的一些常规清理功能删除文件。
您可以创建一个处理所有下载的路由:
const downloadRoot = "/temp/filexfer";
app.get("/download/:id",(req,res) => {
const fullPath = path.resolve(path.join(downloadRoot,req.params.id));
// detect any leading . or any double .. that might jump outside
// the downloadRoot and get to other parts of the server
if (!fullPath.startsWith(downloadRoot)) {
console.log(`Unsafe download request ${fullPath}`);
res.sendStatus(500);
return;
}
res.download(fullPath);
});
清理算法可能如下所示:
const fsp = require('fs').promises;
const path = require('path');
const oneHour = 1000 * 60 * 60;
// run cleanup once per hour
let cleanupTimer = setInterval(async () => {
let oneHourOld = Date.now() - oneHour;
try {
let files = await fsp.readdir(downloadRoot,{withFileTypes: true});
for (let f of files) {
if (f.isFile()) {
let fullName = path.join(downloadRoot,f.name);
let info = await fsp.stat(fullName);
// if file modification time is older than one hour,remove it
if (info.mtimeMs <= oneHourOld) {
fsp.unlink(fullName).catch(err => {
// log error,but continue
console.log(`Can't remove temp download file ${fullName}`,err);
});
}
}
}
} catch(e) {
console.log(e);
}
},oneHour);
// unref the timer so it doesn't stop node.js from exiting naturally
cleanupTimer.unref();
,
有很多方法可以做这种事情,这在很大程度上取决于您想要支持的架构类型。
通过 socket.io 或任何其他 web-socket 发送大文件没问题。它确实需要在您的网络应用程序上进行大量切割和重新组装,但它会起作用。
WebRTC 是另一种共享任何描述文件的方式,它不会给您的服务器带来任何负担,这很好。 (这里有一个教程https://ably.com/tutorials/web-rtc-file-transfer)
这两种方法的问题在于它们是临时共享,房间的新用户将无法获得图像,除非您的服务器再次重新传输数据。
我的建议是直接将文件上传到 s3,然后共享一个可以在每个客户端上解析的链接。这将减轻服务器负担并减少您在后端服务器中的存储需求