Sto scrivendo uno script node.js che preleva i dati da un socket collegato e li invia a un altro socket connesso. Durante i test ho notato che se disconnetto e riconnesso ripetutamente un client mentre un server invia grandi quantità di dati, si verifica una perdita di memoria. Quello che segue è il codice node.js.script node.js e possibile perdita di memoria
var net = require('net');
var logServer = net.createServer();
var clientList = [];
var clientIPList = [];
var serverList = [];
var serverIPList = [];
var port = 6451;
logServer.on('connection', function(client) {
client.setEncoding('utf8');
client.once('data', function(data) {
if (data[0].toString() == 'S') {
var server = client;
client = undefined;
serverList.push(server);
serverIPList.push(server.remoteAddress + ":" + server.remotePort);
console.log('Server connected: %s:%d', server.remoteAddress, server.remotePort);
server.on('data', function(data) {
for(var i=0;i<clientList.length;i+=1) {
try {
clientList[i].write(data);
} catch (err) {
console.log('Error writing to client "data event": ' + clientIPList[i]);
// close and null the socket on write error
try {
clientList[i] = null;
clientList[i].end();
} catch (err) {}
clientList.splice(i, 1);
clientIPList.splice(i, 1);
}
}
})
server.on('end', function() {
try {
var d;
if((d = serverList.indexOf(server)) != -1) {
console.log('Server disconnecting "end event": ' + serverIPList[d]);
try {
serverList[d] = null;
serverList[d].end();
} catch (err) {}
serverList.splice(d, 1);
serverIPList.splice(d, 1);
}
else {
console.log('Server disconnecting "end event": unknown server');
}
} catch (err) {
console.log('Error cleaning up server socket list on "end event"');
}
})
server.on('timeout', function() {
try {
var d;
if((d = serverList.indexOf(server)) != -1) {
console.log('Server disconnecting "timeout event": ' + serverIPList[d]);
try {
serverList[d] = null;
serverList[d].end();
} catch (err) {}
serverList.splice(d, 1);
serverIPList.splice(d, 1);
}
else {
console.log('Server disconnecting "timeout event": unknown server');
}
} catch (err) {
console.log('Error cleaning up server socket list on "timeout event"');
}
})
server.on('error', function(e) {
try {
var d;
if((d = serverList.indexOf(server)) != -1) {
console.log('Server disconnecting ' + e.code + ' "error event": ' + serverIPList[d]);
try {
serverList[d] = null;
serverList[d].end();
} catch (err) {}
serverList.splice(d, 1);
serverIPList.splice(d, 1);
}
else {
console.log('Server disconnecting "error event": unknown server');
}
} catch (err) {
console.log('Error cleaning up server socket list on "error event"');
}
})
server.on('close', function() {
try {
var d;
if((d = serverList.indexOf(server)) != -1) {
console.log('Server disconnecting "close event": ' + serverIPList[d]);
try {
serverList[d] = null;
serverList[d].end();
} catch (err) {}
serverList.splice(d, 1);
serverIPList.splice(d, 1);
}
} catch (err) {
console.log('Error cleaning up server socket list on "close event"');
}
})
server.on('drain', function() {
})
}
else {
clientList.push(client);
clientIPList.push(client.remoteAddress + ":" + client.remotePort);
console.log('Client connected: %s:%d',client.remoteAddress, client.remotePort);
client.on('data', function(data) {
console.log('writing "%s" to %d servers', data.replace(/[\r\n]/g,''), serverList.length);
for(var i=0;i<serverList.length;i+=1) {
try {
serverList[i].write(data);
} catch (err) {
console.log('Error writing to server "data event": ' + serverIPList[i]);
try {
serverList[i] = null;
serverList[i].end();
} catch (err) {}
serverList.splice(i, 1);
serverIPList.splice(i, 1);
}
}
})
client.on('end', function() {
try {
var d;
if((d = clientList.indexOf(client)) != -1) {
console.log('Client disconnecting "end event": ' + clientIPList[d]);
// close and null the socket
try {
clientList[d] = null;
clientList[d].end();
} catch (err) {}
clientList.splice(d, 1);
clientIPList.splice(d, 1);
}
else {
console.log('Client disconnecting "end event": unknown client');
}
} catch (err) {
console.log('Error cleaning up socket client list on "end event"');
}
})
client.on('timeout', function() {
try {
client.end();
} catch (err) {
var d;
if((d = clientList.indexOf(client)) != -1) {
console.log('Error closing client connection "timeout event": ' + clientIPList[d]);
}
else {
console.log('Error closing client connection "timeout event": unknown client');
}
}
try {
var d;
if((d = clientList.indexOf(client)) != -1) {
console.log('Client disconnecting "timeout event": ' + clientIPList[d]);
try {
clientList[d] = null;
clientList[d].end();
} catch (err) {}
clientList.splice(d, 1);
clientIPList.splice(d, 1);
}
else {
console.log('Client disconnecting "timeout event": unknown client');
}
} catch (err) {
console.log('Error cleaning up client socket list on "timeout event"');
}
})
client.on('error', function(e) {
try {
var d;
if((d = clientList.indexOf(client)) != -1) {
console.log('Client disconnecting ' + e.code + ' "error event": ' + clientIPList[d]);
try {
clientList[d] = null;
clientList[d].end();
} catch (err) {}
clientList.splice(d, 1);
clientIPList.splice(d, 1);
}
else {
console.log('Client disconnecting ' + e.code + ' "error event": unknown client');
}
} catch (err) {
console.log('Error cleaning up client socket list on "error event"');
}
})
client.on('close', function() {
try {
var d;
if((d = clientList.indexOf(client)) != -1) {
console.log('Client disconnecting "close event": ' + clientIPList[d]);
try {
clientList[d] = null;
clientList[d].end();
} catch (err) {}
clientList.splice(d, 1);
clientIPList.splice(d, 1);
}
} catch (err) {
console.log('Error cleaning up client socket list on "close event"');
}
})
client.on('drain', function() {
// nothing
})
}
})
})
logServer.listen(port);
Per quanto ne so, sto passare Tutti gli eventi critici 'netti' e sto pulendo le prese correttamente, una volta rilevo una disconnessione. Ecco i due script che sto usando per testare. Il primo si connette e si disconnette come un client più e più volte e il secondo invia i dati come server. Li eseguo entrambi contemporaneamente.
condiscon.rb: Connette e disconnette dopo essersi registrato come client "invia una nuova riga una volta connesso". Corro con' ./condiscon.rb 1000'
#!/usr/bin/ruby
require 'rubygems'
require 'socket'
def connectFlac
host = '10.211.55.10'
port = 6451
sock = TCPSocket.open(host, port)
sock.puts("")
sock
end
sock = connectFlac()
data = []
user_agents = {}
instances_lat = {}
count = ARGV.shift.to_i
while(count > 0)
sock = connectFlac()
sleep(0.05)
sock.close()
sleep(0.05)
count-= 1
end
dataflood.rb: Si collega come server e invia ~ 2600 pacchetti di byte di ABCDE con un contatore. Corro 'dataflood.rb 30000'
#!/usr/bin/ruby
require 'socket'
def connectFlac
host = '10.211.55.10'
port = 6451
sock = TCPSocket.open(host, port)
sock.setsockopt(Socket::IPPROTO_TCP,Socket::TCP_NODELAY,1)
sock.puts("S")
sock
end
def syntax()
print "./script number_of_packets\n"
exit(1)
end
data = ""
(1..100).each {
data+= "abcdefghijklmnopqrstuvwxyz"
}
sock = connectFlac()
numpackets = ARGV.shift.to_i || syntax()
counter = 1
byteswritten = 0
while(numpackets > 0)
r,w,e = IO.select(nil, [sock], nil, nil)
w.each do |sock_write|
print numpackets, "\n"
sock.write(counter.to_s + "|" + data + "\n")
sock.flush()
byteswritten+= counter.to_s.length + 1 + data.length + 1
counter+= 1
numpackets-= 1
end
end
sock.close()
print "Wrote #{byteswritten} bytes\n"
Ecco alcuni dei risultati che sto vedendo. Quando si esegue un profilo di memoria su logserver.js prima di ogni test, viene utilizzato circa 9 megabyte di memoria residente. Sto includendo una pmap per mostrare la sezione di memoria che la perdita sembra occupare.
[[email protected] ~]# ps vwwwp 20658
PID TTY STAT TIME MAJFL TRS DRS **RSS** %MEM COMMAND
20658 pts/4 Sl+ 0:00 0 8100 581943 **8724** 0.8 /usr/local/node-v0.8.12/bin/node logserverdemo.js
[[email protected] ~]# pmap 20658
20658: /usr/local/node-v0.8.12/bin/node logserverdemo.js
0000000000400000 8104K r-x-- /usr/local/node-v0.8.12/bin/node
0000000000de9000 76K rwx-- /usr/local/node-v0.8.12/bin/node
0000000000dfc000 40K rwx-- [ anon ]
**000000001408a000 960K rwx-- [ anon ]**
0000000040622000 4K ----- [ anon ]
Dopo aver eseguito i due script Ruby al di sopra contro il logserver al momento ame qui è ciò che la memoria sembra circa 30 minuti dopo il traffico si ferma. (Ho aspettato per tutti gc accada)
[[email protected] ~]# ps vwwwp 20658
PID TTY STAT TIME MAJFL TRS DRS RSS %MEM COMMAND
20658 pts/4 Sl+ 0:01 0 8100 665839 **89368** 8.7 /usr/local/node-v0.8.12/bin/node logserverdemo.js
[[email protected] ~]# pmap 20658
20658: /usr/local/node-v0.8.12/bin/node logserverdemo.js
0000000000400000 8104K r-x-- /usr/local/node-v0.8.12/bin/node
0000000000de9000 76K rwx-- /usr/local/node-v0.8.12/bin/node
0000000000dfc000 40K rwx-- [ anon ]
**000000001408a000 80760K rwx-- [ anon ]**
0000000040622000 4K ----- [ anon ]
0000000040623000 64K rwx-- [ anon ]
dataflood.rb ha scritto un totale di 78198894 byte di dati e la perdita è molto vicino. Ho scaricato la memoria a 0x1408a000 e ho visto che la maggior parte dei pacchetti che stavo inviando da dataflood.rb erano bloccati in memoria.
[[email protected] ~]# ./memoryprint 20658 0x1408a000 80760000 > 20658.txt
[[email protected] ~]# strings 20658.txt | grep '|abcde' | wc -l
30644
[[email protected] ~]# strings 20658.txt | grep '|abcde' | sort | uniq | wc -l
29638
dopo aver atteso 24 ore la memoria non era ancora stata liberata. Qualsiasi aiuto che chiunque possa darmi sarebbe molto apprezzato.
Ora ho lo stesso problema. Il mio server proxy con codice molto minimale perde, e la creazione di profili non mostra nulla. – majidarif