В вашем коде есть две ошибки, и они определенно не слишком очевидны.
Всякий раз, когда вы пишете клиенту, вы делаете это с помощью этого цикла в writeAll()
:
clients.forEach((client) => {
if(client != exclude) {
client.write(buffer);
}
});
Здесь мы видим, что вы делаете client.write(...)
.Эта команда может обнаружить, что этот конкретный client
закрыл свое соединение.Это означает, что emit('error')
произойдет, и ваш соответствующий обратный вызов будет вызван.
В этом обратном вызове вы вызываете dc(c)
, который, как ожидается, удалит клиента из массива:
clients.splice(index, 1)
Другими словами, вы изменяете массив с именем clients
, пока выполняете clients.forEach()
.Это большой нет нет!Я вообще-то пытаюсь забыть об этой функции forEach()
.Это создало так много проблем с моей стороны!Некоторые люди говорят, что forEach()
также медленнее, чем for()
или while()
петли.Но эта проблема, возможно, была улучшена.
По крайней мере, вы хотите использовать цикл for()
:
for(let i = 0; i < clients.length; ++i)
{
...
}
Обратите внимание, что я сначала не сохраняю clients.length
в переменной, поскольку она может меняться со временем!
Проблема этого подхода заключается в том, что всякий раз, когда возникает splice()
, вы пропускаете некоторых клиентов.
Следующая лучшая вещьсделать это использовать цикл, идущий назад.Для этого while()
хорошо приспособлен:
let i = clients.length
while(i > 0)
{
--i
...
}
Этот цикл будет работать лучше, если: (1) только один элемент получает splice()
d, (2) ни один новый клиент не добавляется всписок.
Последнее, сильное решение, которое я бы предложил, - это сначала скопировать массив:
const client_list = clients.slice()
client_list.forEach((client) => { ... }) // if you really want to use the forEach()?!
Копия не изменится: она локальная и const
.
Но почему в стеке испортилось из-за этого?Возможно, потому что в результате ошибки вы делаете write()
для клиента ... Хорошо, это не связано с forEach()
, но этот код повторяется:
c.on('error', () => {
c.write("400") // are you missing a "\n", btw?
});
Как вы можете видеть,c.write()
является виновником генерируемой ошибки, в этом обратном вызове on()
вы собираетесь зацикливаться вечно ... Вам нужно проверить, является ли c
допустимым или перехватить ошибки:
c.on('error', () => {
try
{
c.write("400") // are you missing a "\n", btw?
}
catch(err)
{
// maybe log the error?
console.log(err)
}
});
При этом я знаю по своему опыту, что после того, как я удалил все вызовы forEach()
из своего кода и сделал копии массивов (объектов), я не могу быть уверен, что они не будут изменены под моими ногами, мой кодработал намного лучше.