Hosang Jeon
Hosang Jeon

Reputation: 1423

Node.js Socket pipe method DOES NOT pipe last packet to the http response

I have Node server which use Express as web app.

This server creates a tcp socket connection with other side TCP server.

I'm trying to pipe tcp data to the user http response.

It works fine for a while, but the LAST tcp packet is NOT piped to http response.

So, download status of web browser stopped as 99.9% downloaded.

My source code is below.

Anyone can help me to solve this problem?

Thanks in advance.

app.get('/download/*', function(req, res){

    var tcpClient = new net.Socket();

    tcpClient.connect(port, ip, function() {    
        // some logic
    });

    tcpClient.on('data', function(data) {

        /* skip ... */

        tcpClient.pipe(res); // This method is called once in the 'data' event loop

        /* skip ... */
    });

    tcpClient.on('close', function() {
        clog.debug('Connection closed.');
    });

    tcpClient.on('end', function() {
        clog.debug('Connection Ended.');
    });

    tcpClient.on('error', function(err){
        clog.err(err.stack);
    });

});

Upvotes: 1

Views: 4553

Answers (1)

Paul Mougel
Paul Mougel

Reputation: 17048

That's not how you are supposed to use .pipe().

When you pipe a stream into another, you don't have to handle the data events yourself: everything is taken care of by the pipe. Moreover, the data event is emitted on every chunk of data, which means that you are possibly piping() the streams multiple times.

You only need to create and initialize the Socket, and then pipe it to your response stream:

tcpClient.connect(port, ip, function () {    
    // some logic

    this.pipe(res);
});

Edit: As you precised in the comments, the first chunk contains metadata, and you only want to pipe from the second chunk thereon. Here's a possible solution:

tcpClient.connect(port, ip, function () {    
    // some logic

    // Only call the handler once, i.e. on the first chunk
    this.once('data', function (data) {
        // Some logic to process the first chunk
        // ...

        // Now that the custom logic is done, we can pipe the tcp stream to the response
        this.pipe(res);
    });
});

As a side note, if you want to add custom logic to the data that comes from the tcpClient before writing it to the response object, check out the Transform stream. You will then have to:

  • create a transform stream with your custom transforming logic
  • pipe all streams together: tcpClient.pipe(transformStream).pipe(res).

Upvotes: 4

Related Questions