简体   繁体   English

如何使用 socket.io 和大于 1mb 的 nodejs 实现房间到房间的文件共享系统?

[英]How to implement room to room file sharing system using socket.io and nodejs larger than 1mb?

I want to implement socket.io room to room file sharing system so users can send images to their respective rooms to all user can see it and I have tried using base64 encoding method to emit sender image file to specific room but it can send only approximately 700kb to 800kb file.我想实现 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

I have also tried binary streaming but got no luck please help me guys with some codes samples我也尝试过二进制流,但没有运气请帮我一些代码示例

You will probably find it easier for the client to upload the file to your http server with a room name and then have your http server send a message to all the other clients in the room via socket.io with a URL where the client can download the file using http. You will probably find it easier for the client to upload the file to your http server with a room name and then have your http server send a message to all the other clients in the room via socket.io with a URL where the client can download the file使用 http。 socket.io is just not a streaming protocol, it's a packet or message-based protocol so to send large things, it has to be broken up into messages and then reassembled on the client. socket.io 不是流协议,它是基于数据包或消息的协议,因此要发送大的东西,必须将其分解为消息,然后在客户端上重新组合。 This can be done, but it's just extra non-standard work that http uploads and downloads already know how to do.这个是可以做到的,只是http上传下载已经知道怎么做的额外的非标准工作。

Here would be the steps:以下是步骤:

  1. Client uploads file to server via http post with the room name as a field in the form.客户端通过 http 帖子将文件上传到服务器,其中房间名称作为表单中的字段。
  2. Server receives uploaded file, assigns it a unique ID and stores it in a temporary location on the server on disk.服务器接收上传的文件,为其分配一个唯一的 ID,并将其存储在服务器上磁盘上的临时位置。
  3. When file upload completes server notifies all other clients in the room via socket.io that the file is uploaded and ready for download and sends them the URL for download that has the uniqueID in it.当文件上传完成时,服务器通过 socket.io 通知房间中的所有其他客户端文件已上传并准备好下载,并将 URL 发送给他们以供下载,其中包含 uniqueID。
  4. Each client sends request to download the file via http using the unique URL they received.每个客户端使用他们收到的唯一 URL 通过 http 发送下载文件的请求。
  5. Server serves the file to each client as requested over http.服务器根据请求通过 http 将文件提供给每个客户端。
  6. Server either keeps track of whether all clients have now finished downloading or just removes the file after some period of time based on timestamp of the file (to just clean up disk space) with some regular cleanup function on a recurring timer.服务器要么跟踪所有客户端现在是否已完成下载,要么根据文件的时间戳在一段时间后删除文件(仅清理磁盘空间),并在循环计时器上定期清理 function。

You can create a single route that handles all the downloads:您可以创建处理所有下载的单个路由:

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);
});

A cleanup algorithm could look like this:清理算法可能如下所示:

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();

There are a lot of ways to do this sort of thing and it depends heavily on what sort of architecture you want to support.有很多方法可以做这种事情,这在很大程度上取决于你想要支持什么样的架构。

Sending large files through socket.io or any other web-socket is fine.通过 socket.io 或任何其他网络套接字发送大文件都可以。 it does require a bunch of chopping and reassembling on your web app but it will work.它确实需要在您的 web 应用程序上进行大量切割和重新组装,但它会起作用。

WebRTC is another way to share files of any description, and it will not burden your server in anyway which is good. WebRTC 是共享任何描述文件的另一种方式,它不会对您的服务器造成任何负担,这很好。 (here is a tutorial on it https://ably.com/tutorials/web-rtc-file-transfer ) (这里有一个教程https://ably.com/tutorials/web-rtc-file-transfer

The issue with either of these methods is that they are transient shares, are new user to the room will not get the image, unless your server re-transmits the data again.这两种方法的问题在于它们是临时共享,房间的新用户将无法获取图像,除非您的服务器再次重新传输数据。

My suggestion would be to upload the file to s3 directly and then share a link to it that can be resolved on each of the clients.我的建议是将文件直接上传到 s3,然后共享一个可以在每个客户端上解决的链接。 This will keep the server burden down and reduce your storage requirements in the backend server这将减轻服务器负担并减少后端服务器中的存储需求

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM