如何使用 socket.io 和大于 1mb 的 nodejs 实现房间到房间的文件共享系统?
How to implement room to room file sharing system using socket.io and nodejs larger than 1mb?
我想实施 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 向房间中的所有其他客户端发送消息更容易a URL 客户端可以使用 http 下载文件。 socket.io 只是不是流协议,它是一种基于数据包或消息的协议,因此要发送大量内容,必须将其分解为消息,然后在客户端重新组合。这个是可以做的,只是http上传下载已经知道怎么做的额外的非标准工作
步骤如下:
- 客户端通过 http post 将文件上传到服务器,并将房间名称作为表单中的一个字段。
- 服务器接收上传的文件,为其分配一个唯一的 ID 并将其存储在服务器磁盘上的临时位置。
- 当文件上传完成时,服务器通过 socket.io 通知房间中的所有其他客户端文件已上传并准备好下载,并向他们发送 URL 以供下载,其中包含唯一 ID。
- 每个客户端使用他们收到的唯一 URL 通过 http 发送下载文件的请求。
- 服务器根据通过 http 请求向每个客户端提供文件。
- 服务器跟踪是否所有客户端现在都已完成下载,或者只是在一段时间后根据文件的时间戳删除文件(仅清理磁盘 space)并使用一些常规清理功能在循环计时器上。
您可以创建处理所有下载的单个路由:
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 或任何其他网络套接字发送大文件都可以。它确实需要在您的网络应用程序上进行大量的切割和重新组装,但它会起作用。
WebRTC 是另一种共享任何描述文件的方式,无论如何它不会给您的服务器增加负担,这很好。 (这里有一个教程https://ably.com/tutorials/web-rtc-file-transfer)
这两种方法的问题在于它们是临时共享,房间的新用户将无法获取图像,除非您的服务器再次重新传输数据。
我的建议是直接将文件上传到 s3,然后共享一个 link 给它,可以在每个客户端上解析。这将减轻服务器负担并减少后端服务器的存储需求
我想实施 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 向房间中的所有其他客户端发送消息更容易a URL 客户端可以使用 http 下载文件。 socket.io 只是不是流协议,它是一种基于数据包或消息的协议,因此要发送大量内容,必须将其分解为消息,然后在客户端重新组合。这个是可以做的,只是http上传下载已经知道怎么做的额外的非标准工作
步骤如下:
- 客户端通过 http post 将文件上传到服务器,并将房间名称作为表单中的一个字段。
- 服务器接收上传的文件,为其分配一个唯一的 ID 并将其存储在服务器磁盘上的临时位置。
- 当文件上传完成时,服务器通过 socket.io 通知房间中的所有其他客户端文件已上传并准备好下载,并向他们发送 URL 以供下载,其中包含唯一 ID。
- 每个客户端使用他们收到的唯一 URL 通过 http 发送下载文件的请求。
- 服务器根据通过 http 请求向每个客户端提供文件。
- 服务器跟踪是否所有客户端现在都已完成下载,或者只是在一段时间后根据文件的时间戳删除文件(仅清理磁盘 space)并使用一些常规清理功能在循环计时器上。
您可以创建处理所有下载的单个路由:
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 或任何其他网络套接字发送大文件都可以。它确实需要在您的网络应用程序上进行大量的切割和重新组装,但它会起作用。
WebRTC 是另一种共享任何描述文件的方式,无论如何它不会给您的服务器增加负担,这很好。 (这里有一个教程https://ably.com/tutorials/web-rtc-file-transfer)
这两种方法的问题在于它们是临时共享,房间的新用户将无法获取图像,除非您的服务器再次重新传输数据。
我的建议是直接将文件上传到 s3,然后共享一个 link 给它,可以在每个客户端上解析。这将减轻服务器负担并减少后端服务器的存储需求