如何使用 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上传下载已经知道怎么做的额外的非标准工作

步骤如下:

  1. 客户端通过 http post 将文件上传到服务器,并将房间名称作为表单中的一个字段。
  2. 服务器接收上传的文件,为其分配一个唯一的 ID 并将其存储在服务器磁盘上的临时位置。
  3. 当文件上传完成时,服务器通过 socket.io 通知房间中的所有其他客户端文件已上传并准备好下载,并向他们发送 URL 以供下载,其中包含唯一 ID。
  4. 每个客户端使用他们收到的唯一 URL 通过 http 发送下载文件的请求。
  5. 服务器根据通过 http 请求向每个客户端提供文件。
  6. 服务器跟踪是否所有客户端现在都已完成下载,或者只是在一段时间后根据文件的时间戳删除文件(仅清理磁盘 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 给它,可以在每个客户端上解析。这将减轻服务器负担并减少后端服务器的存储需求