Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Closing socket in client crashes nodejs server

Tags:

On C client I do:

socket()
connect() on port 6969
send()
//I have seen that I didn't call recv so nodejs try me to send data but My program was gone
and finally closesocket()

On nodejs server I receive the message so the connection is established:

const port = 6969;
var net = require('net');
var server = net.createServer(function(connection) {
    console.log('client connected');
    connection.on('close', function() {
        console.log('conn closed');
    });
    connection.on('end', function() {
        console.log('conn ended');// that is not called
    });
    connection.on("error", function(err) {
        console.log("Caught flash policy server socket error: ");
        console.log(err.stack);
    });
    connection.on('data', function(data) {
        data = data.toString();
        console.log('client sended the folowing string:' + data);
        connection.write("Response");
        console.log('Sended response to client');
    });
});
server.listen(port, function() {
    console.log('server is listening');
});

This is the result of my terminal:

server is listening
client connected
client sended the folowing string:err404
Sended response to client
Caught flash policy server socket error:
Error: read ECONNRESET
    at exports._errnoException (util.js:1018:11)
    at TCP.onread (net.js:568:26)
conn closed

So I have read Node js ECONNRESET already but I don't understand if this is normal why my nodejs server crash?

Edit: I found this snippet:

connection.on("error", function(err) {
    console.log("Caught flash policy server socket error: ");
    console.log(err.stack);
});

This code on client side will produce the same error:

#ifdef WIN32
Sleep(5000);
int iResult = shutdown(sock, SD_BOTH);
printf("shutdown is called\n");
Sleep(5000);
#elif defined (linux)
sleep(5);
int iResult = shutdown(sock, SHUT_RDWR);
printf("shutdown is called\n");
sleep(5);
#endif // WIN32
    if (iResult == SOCKET_ERROR) {closesocket(sock);printf("SOCKET_ERROR");}
    printf("iResult=%d",iResult);

Edit: Now I catch either close event and end event: but the same error is still throwed.

Edit: I've Updated my code. And I found where is the problem:NodeJs is trying to send me data but I've already called shutdown().

like image 805
Et7f3XIV Avatar asked Jul 06 '17 08:07

Et7f3XIV


1 Answers

There 2 things to consider, one in your server and one in your client code.

Server code:

You have to use the end event instead of the close event, see https://nodejs.org/api/net.html#net_event_end:

connection.on('end', function (){
   console.log('client disconnected');
});

end event:

Emitted when the other end of the socket sends a FIN packet, thus ending the readable side of the socket.

close event:

Emitted once the socket is fully closed. The argument had_error is a boolean which says if the socket was closed due to a transmission error.

So that means, that the close event will occur after the end event.


Client code:

You have to call shutdown before closing the socket to prevent further reads or writes which then would cause an error because the socket is already down.

The Windows version of shutdown is described here at MSDN and the Linux variant here in a manpage.

Windows:

int ret = shutdown(sockfd, SD_BOTH); /* Shutdown both send and receive operations. */

Linux:

int ret = shutdown(sockfd, SHUT_RDWR); /* Disables further send and receive operations. */

Importance of flushing sent data:

The shutdown function does not guarantees that data that is already in the buffer does not get send. It is needed that all data get's flushed before the call to close occur. In this answer on SO is written down a nice way to do that rather than just sleep 20 ms or so.
In order to test if that is your problem you can use Sleep(2000) in Windows and sleep(2) in Linux to sleep 2 seconds between shutdown and close.


On this page is a nice comparison between close/closesocket and shutdown:

You're ready to close the connection on your socket descriptor. This is easy. You can just use the regular Unix file descriptor close() function:

close(sockfd); 

This will prevent any more reads and writes to the socket. Anyone attempting to read or write the socket on the remote end will receive an error.

Just in case you want a little more control over how the socket closes, you can use the shutdown() function. It allows you to cut off communication in a certain direction, or both ways (just like close() does.) Synopsis:

int shutdown(int sockfd, int how);

[...]

shutdown() returns 0 on success, and -1 on error (with errno set accordingly.)

like image 193
Andre Kampling Avatar answered Oct 04 '22 19:10

Andre Kampling