1

I am trying to send image data from my TCP client to my TCP server both written in node.js

I have already tried doing it this way

client:

function onData(socket, data) {
  var data = Buffer.from(data).toString()
  var arg = data.split(',')
  var event = arg[0]
  console.log(event)

  if (event == 'screenshot') {
    console.log(hostname)
    console.log('control client uid ' + arg[1] + 'then we screenshot')
    screenshot()
      .then(img => {
        console.log(img)
        socket.write('screenshotData,' + ',' + hostname + ',' + img)
        socket.write('stdout,' + arg[2] + ',Screenshot')
      })
      .catch(err => {
        console.log(err)
        socket.write('error', err)
      })
  }
}

server:

sock.on('data', function(data) {
  //right here i need to parse the first 'EVENT' part of the text so i can get cusotom tcp events and
  var data = Buffer.from(data).toString()
  var arg = data.split(',')
  var event = arg[0]

  if (event == 'screenshotData') {
    agentName = arg[1]
    img = arg[2]
    console.log('agent-name ' + agentName)
    console.log('screnshotdata' + img)

    var dt = dateTime.create()
    var formattedTime = dt.format('Y-m-d-H-M-S')
    var folder = 'adminPanel/screenshots/'
    var filename = formattedTime + '-' + agentName + '.png'
    console.log(filename)
    fs.writeFile(folder + filename, img, function(err) {
      console.log(err)
    })
  }
})

I had to build some rudimentary event system in TCP. If you know a better way then let me know. Anyways, the client takes a screenshot and then it does socket.write('screenshotData', + ',' + hostname + ',' img).

But it sends the data in multiple chunks as my console is showing random gibberish as a new event many times so I don't even know how I would do this. Any help would be great.

zhirzh
  • 3,273
  • 3
  • 25
  • 30
Nik Hendricks
  • 244
  • 2
  • 6
  • 29
  • You need to reassemble the buffer by appending to it, detect when it's complete, and make sure your img can't contain your ',' separater or preferably use a length indicator. https://stackoverflow.com/a/57517507/1269466 – lossleader Aug 29 '19 at 21:36
  • and also: https://stackoverflow.com/a/17313295/1269466 – lossleader Aug 30 '19 at 17:21

2 Answers2

2

You are treating your TCP stream as a message-oriented protocol, in addition to mixing encodings (your image Buffer is simply concatenated into the string).

I suggest you switch TCP streams with websockets. The interface remains largely the same (read replaced with message events, stuff like that) but it actually behaves like you are expecting.

Working server:

const WebSocket = require('ws');
const fs = require('fs');

const PORT = 3000;

const handleMessage = (data) => {
    const [action, payload] = data.split(',');
    const imageData = Buffer.from(payload, 'base64');

    const imageHandle = fs.createWriteStream('screenshot.jpg');
    imageHandle.write(imageData);
    imageHandle.end();

    console.log(`Saved screenshot (${imageData.length} bytes)`);
};

const wss = new WebSocket.Server({port: PORT});
wss.on('connection', (ws) => {
    console.log('Opened client');
    ws.on('message', (data)=>handleMessage(data));
});
console.log('Server started');

client:

const WebSocket = require('ws');
const screenshot = require('screenshot-desktop');

const PORT = 3000;

const sendImage = ( client, image ) => {
    const payload = image.toString('base64');
    const message = ["screenshot", payload].join(',');
    console.log(`Sending ${image.length} bytes in message ${message.length} bytes`);
    client.send(
        message, 
        () => {
            console.log('Done');
            process.exit(0);
        }
    );
};

const client = new WebSocket('ws://localhost:'+PORT+'/');
client.on('open', () => {
    console.log('Connected');
    screenshot().then( image => sendImage(client, image) );
});
gcasar
  • 729
  • 1
  • 9
  • 22
1

if you specifically want to transfer an image type file, then the best-suggested way is to deal with b64 data. i.e convert your image to a b64 and send the data over a channel, and after receiving it in the server, you can convert it into a .jpg/.png again.

For reference https://www.npmjs.com/package/image-to-base64

  • it currently is being sent as base64 but in multiple chunks. im not sure how to make the server know what is part of the chunk and when the chunk is done – Nik Hendricks Sep 01 '19 at 07:26