Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send File through Websocket along with additional info?

I'm developing a Web application to send images, videos, etc. to two monitors from an admin interface. I'm using ws in Node.js for the server side. I've implemented selecting images available on the server and external URLs and sending them to the clients, but I also wanted to be able to directly send images selected from the device with a file input. I managed to do it using base64 but I think it's pretty inefficient.

Currently I send a stringified JSON object containing the client to which the resource has to be sent, the kind of resource and the resource itself, parse it in the server and send it to the appropriate client. I know I can set the Websocket binaryType to blob and just send the File object, but then I'd have no way to tell the server which client it has to send it to. I tried using typeson and BSON to accomplish this, but it didn't work.

Are there any other ways to do it?

like image 626
user2859982 Avatar asked May 13 '18 12:05

user2859982


People also ask

Can we send file through WebSocket?

You can send raw binary data through the WebSocket. It's quite easy to manage. One option is to prepend a "magic byte" (an identifier that marks the message as non-JSON).

How do you send data over WebSockets?

To send a message through the WebSocket connection you call the send() method on your WebSocket instance; passing in the data you want to transfer. socket. send(data); You can send both text and binary data through a WebSocket.

How do you send a blob in WebSocket?

WebSockets support sending binary messages, too. To send binary data, one can use either Blob or ArrayBuffer object. Instead of calling the send method with string, you can simply pass an ArrayBuffer or a Blob .

How much data can be sent through WebSocket?

As of v3, socket.io has a default message limit of 1 MB. If a message is larger than that, the connection will be killed.


3 Answers

You can send raw binary data through the WebSocket.

It's quite easy to manage.

One option is to prepend a "magic byte" (an identifier that marks the message as non-JSON). For example, prepend binary messages with the B character.

All the server has to do is test the first character before collecting the binary data (if the magic byte isn't there, it's probably the normal JSON message).

A more serious implementation will attach a header after the magic byte (i.e., file name, total length, position of data being sent etc').

This allows the upload to be resumed on disconnections (send just the parts that weren't acknowledged as received.

Your server will need to split the data into magic byte, header and binary_data before processing. but it's easy enough to accomplish.

like image 171
Myst Avatar answered Sep 20 '22 13:09

Myst


Hope this help someone. According to socket.io document you can send either string, Buffer or mix both of them

On Client side:

function uploadFile(e, socket, to) {
  let file = e.target.files[0];

  if (!file) {
    return
  }
  if (file.size > 10000000) {
    alert('File should be smaller than 1MB')
    return
  }

  var reader = new FileReader();
  var rawData = new ArrayBuffer();

  reader.onload = function (e) {
    rawData = e.target.result;
    socket.emit("send_message", {
      type: 'attachment',
      data: rawData
    } , (result) => {
      alert("Server has received file!")
    });
    alert("the File has been transferred.")
  }

  reader.readAsArrayBuffer(file);
}

on server side:

socket.on('send_message', async (data, cb) => {
  if (data.type == 'attachment') {
      console.log('Found binary data')
      cb("Received file successfully.")
      return
    }
// Process other business...
});
like image 27
Travis Nguyen Avatar answered Sep 23 '22 13:09

Travis Nguyen


I am using pure WebSocket without io, where you cannot mix content - either String or Binary. Then my working solution is like this:

CLIENT:

    import { serialize } from 'bson';
    import { Buffer } from 'buffer';

    const reader = new FileReader();
    let rawData = new ArrayBuffer();
    ws = new WebSocket(...)
    reader.onload = (e) => {
      rawData = e.target.result;
      const bufferData = Buffer.from(rawData);
      const bsonData = serialize({  // whatever js Object you need
        file: bufferData,
        route: 'TRANSFER',
        action: 'FILE_UPLOAD',
      });
      ws.send(bsonData);
    }

Then on Node server side, the message is catched and parsed like this:

        const dataFromClient = deserialize(wsMessage, {promoteBuffers: true}) // edited
        fs.writeFile(
          path.join('../server', 'yourfiles', 'yourfile.txt'),
          dataFromClient.file, // edited
          'binary',
          (err) => {
            console.log('ERROR!!!!', err);
          }
        );

The killer is promoteBuffer option in deserialize function.

like image 45
Fide Avatar answered Sep 20 '22 13:09

Fide