Node: TCP Sockets without a listener on the "data" event, does not emit an "end" event, if there is a socket.write() followed by a socket.end()

Created on 31 Mar 2020  路  1Comment  路  Source: nodejs/node

  • Version: 13.7.0
  • Platform: Win 10 (64bit)
  • Subsystem: _stream_readable.js

What steps will reproduce the bug?

This server only has a listener for the end event

const net = require("net");
const port = 3000;

let server = net.createServer();
server.on("connection", connection_handler);
function connection_handler(socket){
    console.log("New Client Connected");
    /*
    socket.on("data", data_handler);
    function data_handler(data){

    };
    */
    socket.on("end", end_handler);
    function end_handler(){
        console.log("Client Disconnected");    //never called
    };
};

server.listen(port);
console.log(`Server Listening on port ${port}`);

This client connects and then immediately disconnects, sending data that should be ignored.

const net = require("net");
const host = "localhost";
const port = 3000;

const socket = net.createConnection({ host, port });
socket.on("connect", connect_handler);
function connect_handler(){
    console.log("Connection with Server Established");
    socket.end("Ignore This Message");
    //socket.end();     //works as intended, replace previous line
}

The call to socket.end() however is also ignored, and the server does not print "Client Disconnected".

How often does it reproduce? Is there a required condition?

Should be reproducible every time.

What is the expected behavior?

On the writable end the docs specify

socket.end([data[, encoding]][, callback])

If data is specified, it is equivalent to calling socket.write(data, encoding) followed by socket.end().

https://nodejs.org/api/net.html#net_socket_end_data_encoding_callback

On the readable end the the docs specify

The data will be lost if there is no listener when a Socket emits a 'data' event.
https://nodejs.org/api/net.html#net_event_data

But I doubt it was intended to ignore subsequent calls to end()

What do you see instead?

Server will ignore the message "Ignore This Message" as it should (since there's no listener for data), but it also ignores the FIN sent via socket.end()

The message "Client Disconnected" never prints.

I've decomposed the client into write() followed by end() and have the same problem

const net = require("net");
const host = "localhost";
const port = 3000;

const socket = net.createConnection({ host, port });
socket.on("connect", connect_handler);
function connect_handler(){
    console.log("Connection with Server Established");
    socket.write("Ignore This Message",function(){
        console.log("Write Sent");
        socket.end(function(){
            console.log("End Sent");
        });
    });
}

My current workaround is to either add a completely blank data handler. (1st comment on server) - Or use socket.end() without any data. (2nd comment on client)

Additional information

Using wireshark I do see the sender is sending the data as intended

Capture

I've also reverse where the data and end segments originates from and the issue persists

I'm guessing it's related to https://github.com/nodejs/node/blob/master/lib/_stream_readable.js, but have been pouring through this for a good day and can't seem to find what code triggers the call to emit('end')

It's not a timing issue, I've stuck some timeouts in between write and end and get the same error

const net = require("net");
const host = "localhost";
const port = 3000;

const socket = net.createConnection({ host, port });
socket.on("connect", connect_handler);
function connect_handler(){
    console.log("Connection with Server Established");
    socket.write("Ignore This Message",function(){
        console.log("Write Sent");
        setTimeout( function(){
            socket.end(function(){
                console.log("End Sent");
            });
        },5000);
    });
}

Most helpful comment

This is expected. There is buffered data to read, so you should consume that data before the 'end' event is emitted. If you don't want to use a 'data' listener you can resume the socket.

function connection_handler(socket){
  console.log("New Client Connected");

  socket.resume();
  socket.on("end", end_handler);
  function end_handler(){
    console.log("Client Disconnected");
  };
}

>All comments

This is expected. There is buffered data to read, so you should consume that data before the 'end' event is emitted. If you don't want to use a 'data' listener you can resume the socket.

function connection_handler(socket){
  console.log("New Client Connected");

  socket.resume();
  socket.on("end", end_handler);
  function end_handler(){
    console.log("Client Disconnected");
  };
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

cong88 picture cong88  路  3Comments

addaleax picture addaleax  路  3Comments

ksushilmaurya picture ksushilmaurya  路  3Comments

sandeepks1 picture sandeepks1  路  3Comments

dfahlander picture dfahlander  路  3Comments