Why is end event handler(socket) and close event handler(server) is being called at the same time?
I am expecting close event handler to be called after 30 seconds.
Can someone please help me?
Although after 30 seconds my TCP server is not accepting any new connection(keeps existing connections open) but I was expecting close event handler invocation after 30 sec.
close event handler of server as well as end event handler of socket is invoked when I forcefully close all existing tcp clients.
TCP connection ended
TCP connection ended
server closed but it will keep existing connection
var net = require("net");
function getSocketInfo(socketObject){
console.log('bytesRead= ' + socketObject.bytesRead);
console.log('bytesWritten= ' + socketObject.bytesWritten);
}
var tcpServer = net.createServer({allowHalfOpen:false},function(socketObject){
socketObject.setEncoding('utf8');
getSocketInfo(socketObject);
socketObject.on('data',function(data){
console.log('data received');
console.log(data);
console.log(data.length);
socketObject.write('Server Reply: ' + data,'utf8',function(){
console.log('data successfully written on socket');
});
getSocketInfo(socketObject);
});
socketObject.on('end',function(){
console.log('TCP connection ended');
});
});
setTimeout(function(){tcpServer.close();},30000);
tcpServer.on('close',function(){ console.log('server closed but it will keep existing connection');});
tcpServer.on('error',function(error){
console.log(error.code);
});
tcpServer.listen(8000,function(){
console.log('TCP server has been bound');
});
I got the answer after looking into the event section.
close handler will be called when ALL EXISTING TCP connections are closed, not immediately after close method invocation. This was strange but as per documentation it is correct behavior.
Event: 'close'#
Emitted when the server closes. Note that if connections exist, this
event is not emitted until all connections are ended.
Related
He is a bit of code where a server is created to listen on port 2222:
import { createServer } from 'net';
const server = createServer((c) => {
c.setEncoding('utf8');
c.on('data', (data) => {
console.log('server', data);
c.write(data);
});
c.on('error', (e) => { throw e; });
});
server.listen(2222);
and the code to create a connection to the server to send a simple 'hello' that the server will respond back to. After 2 seconds, the socket gets destroyed.
import { createConnection } from 'net';
const socket = createConnection({ localPort: 9999, port: 2222, host: 'localhost' });
socket.setEncoding('utf8');
socket.on('data', (data) => {
console.log('socket data', data);
});
socket.on('connect', () => {
socket.write('hello');
});
socket.setTimeout(2000);
socket.on('timeout', () => { socket.destroy(); console.log('destroyed'); });
socket.on('error', (e) => { throw e; });
This code works well the first time it is called.
It will fail on subsequent calls with:
Error: connect EADDRINUSE 127.0.0.1:2222 - Local (0.0.0.0:9999)
errno: -48,
code: 'EADDRINUSE',
syscall: 'connect',
address: '127.0.0.1',
port: 2222
It took me a while to figure it out, but the problem comes from trying to bind the socket on an outbound port: localPort: 9999. Without specifying this parameter, the OS will select a free port, and the program won't crash.
When specifying it, a cooldown of ~15s is required before the socket being re-usable again.
Is there a way to properly destroy the socket so that it becomes immediately available again?
If not, is there a way to verify that the socket is "cooling down", but will eventually be available again? I'd like to distinguish the case where I just have to wait from the one where the socket has been actively taken by another process, and won't be released to the pool of free sockets.
Any theory on why the socket is not available after the program exists is welcome!
The socket is going into a CLOSE_WAIT state, so you have to wait until it is available again before you can reconnect. You can try to avoid this by:
Removing the source socket and letting the platform pick a random ephemeral one for you (as you have already found out).
Closing the connection at the server end first (so the CLOSE_WAIT ends up there). See server.close();
Resetting the client connection. See socket.resetAndDestroy()
Why are you specifying a local port in the first place? You almost never want to do that. If you don't, it'll work.
Any theory on why the socket is not available after the program exists is welcome!
The OS keeps the port in use for a while to be able to receive packets and tell the sender that the socket is gone.
Is there a way to properly destroy the socket so that it becomes immediately available again?
You can set the "linger" socket option to 0, so it'll become available immediately again, but again, you shouldn't get yourself in this situation in the first time. Consider whether you want to specify the local port. You usually don't.
is there a way to verify that the socket is "cooling down"
It'll be in the CLOSE_WAIT state.
I am using mongoose 4.13.7
I want to connect to mongo but if an error occurs I want to reconnect.
But after 5 reconnects, if an error occurs, the process should exit.
This is the code:
var count = 0;
handleDisconnect();
function handleDisconnect(){
count++;
console.log('Trying to connect to mongo. Attempt : ' + count);
mongoose.connect(config.mongo.uri,{useMongoClient:true});
mongoose.connection.on('error',(error)=>{
if (count >= 5){
console.log('Mongo ERROR');
console.error(error);
process.exit(1);
}
else{
setTimeout(handleDisconnect,1000);
}
});
mongoose.connection.on('open',()=>{
console.log('Connected to mongo at ' + Date.now());
});
}
I have posted the output of the code as well. I don't understand how the attempt count is exceeding 5? There is also a memory leak warning and node:6804 error message. What am I doing wrong?
Output of the code
You attach an event listener for the error event each time the event is emitted. This causes the memory leak warning and also makes the callback function run multiple times per each event ocurrance. You should not add the event handler inside the handleDisconnect() funciton.
Example:
function handleDisconnect(mongoError) {
// check error reason, increment counters, check if errors limit reached
}
mongoose.connection.on('error', handleDisconnect);
You need to check disconnected event when Mongoose lost connection to the MongoDB server. This event may be due to your code explicitly closing the connection, the database server crashing, or network connectivity issues.
mongoose.connection.on('disconnected', () => console.log('Server disconnected from mongoDB'));
error Event: Emitted if an error occurs on a connection, like a parseError due to malformed data or a payload larger than 16MB.
https://mongoosejs.com/docs/connections.html#connection-events
When I write data to a TCP socket in Node, which is not closed but the client on the other side is not connected anymore (because of network failure for example), how do I know?
The socket's error event doesn't fire in this case for me. If I'm right, TCP gives up sending data, if there is absolutely no ACK packets from the other side, doesn't it? Or am I misunderstanding something?
As explained in the Nodejs Net documentation.
Socket events are close, connect, data, drain, end, error, lookup, and timeout.
Since you're not getting an error event, try listening to the end event which is emitted when the other end of the socket sends a FIN packet.
socket.on('end', () => console.log('socket has ended'))
Alternatively, if you expect a network failure or other unpredictable network edge cases on their end; you can always set a timeout and handle it that way.
socket.setTimeout(60000) // 60 seconds
socket.on('timeout', () => {
console.warn('socket has timed out')
socket.write('socket has timed out')
socket.end()
})
close event listeners are passed a hadError arg that indicates if the socket was closed because of a transmission error. For example:
socket.on('close', hadError => {
if (hadError) {
// Handle transmission error here
}
});
I'm having a weird issue with a TCP client - I use socket.connect() to connect to the server instance. However, since the server is not running, I receive an error of ECONNREFUSED (so far so good).
I handle it using on('error') and set a timeout to try and reconnect in 10 seconds. This should continue to fail as long as the server is down. which is the case.
However, as soon as the server is running, it looks like all of the previous sockets are still active, so now I have several client sockets connected to the server.
I tried to call the destroy at the beginning of the on('error') handler function.
Any ideas how to deal with that?
Thanks!
EDIT: Code snippet:
var mySocket;
var self = this;
...
var onError = function (error) {
mySocket.destroy(); // this does not change anything...
console.log(error);
// Wait 10 seconds and try to reconnect
setTimeout(function () {
console.log("reconnecting...");
self.once('InitDone', function () {
// do something
console.log("init is done")
});
self.init();
}, 10000);
}
Inside init function:
...
console.log("trying to connect");
mySocket = tls.connect(options, function () {
console.log("connected!");
self.emit('InitDone');
});
mySocket.setEncoding('utf8');
mySocket.on('error', onError);
...
The result of this is something like the following:
trying to connect
ECONNREFUSED
reconnecting...
trying to connect
ECONNREFUSED
reconnecting...
trying to connect
ECONNREFUSED
reconnecting...
--> Starting the server here
trying to connect
connected
init is done
connected
init is done
connected
init is done
connected
init is done
However I would expect only one connection since the previous sockets failed to connect. Hope this clarifies the question.
Thanks!
I'm experimenting with the close event in Node.js. I'm very new to Node.js so I'm not sure if this is a decent question or a sad one.
Documentation for close event:
http://nodejs.org/api/http.html#http_event_close_2
I want to output to the console a message if the browser is closed before the end event is reached.
While the server ran and before it got to 15 seconds, I tried closing the browser and killing the process through Chrome Tools. No message is output to the console and if I open up other connections by visiting localhost:8080 with other windows, I quickly get a 'hello' indicating my node server thinks there are at least two connections.
I'm either not understanding how to kill processes in Chrome or how the event close works.
Or if End and Close are the same - node.js https no response 'end' event, 'close' instead? - why isn't my "They got impatient!" message still ouput in the console?
How can you output to a console if the process was ended before the event end was reached?
var http = require('http'),
userRequests = 0;
http.createServer(function(request,response){
userRequests++;
response.writeHead(200, {'Content-Type' : 'text/plain'});
if ( userRequests == 1 ){
response.write('1st \n');
setTimeout ( function() {
response.write('2nd Thanks for waiting. \n');
response.on('close', function() {
console.log("They got impatient!");
});
response.end();
}, 15000);
response.write('3rd \n');
}
else {
// Quick response for all connections after first user
response.write('Hello');
response.end();
}
}).listen(8080, function() {
console.log('Server start');
});
Thank you.
First - move the event handler for the close message outside the timeout function - you're not hooking up the close handler until after your timeout expires, and probably missing the event.
Second, you never decrement userRequests anywhere; shouldn't there be a userRequests--; line somewhere? This would be throwing off your logic, since it'll always look like there's more than one request.