我有一个
toy IRC bot
我一直在攻击它,它能够同时连接到多个服务器,包括未加密的服务器和通过TLS的服务器。原来是我的
connection code looked like this
:
constructor({host, port, tlsEnabled, nick, channels}: {host: string, port: number, tlsEnabled: boolean, nick: string, channels: Channels}) {
this.host = host;
this.port = port
? port
: tlsEnabled
? 6697
: 6667;
this.tlsEnabled = tlsEnabled;
this.nick = nick;
this.channels = channels;
this.client = this.tlsEnabled
? tls.connect({host: this.host, port: this.port, timeout: 180000}, () => this.sendClientRegistration())
: net.connect({host: this.host, port: this.port, timeout: 180000}, () => this.sendClientRegistration());
[...]
this.client.on('close', (hadError) => {
logMessage('INFO', this.host, `Connection to ${host} closed`);
try {
setTimeout(() => this.client.connect({host: this.host, port: this.port}, () => this.sendClientRegistration()), 60000);
} catch (err) {
logMessage('INFO', this.host, `Failed to reconnect to ${this.host}`);
}
});
}
它基本上工作正常,除非与服务器的连接被中断足够长的时间,否则我最终会遇到问题
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 connect listeners added to [Socket]
消息,它永远不会重新连接。
我
refactored the connection code
看起来像这样:
constructor({host, port, tlsEnabled, nick, channels}: {host: string, port: number, tlsEnabled: boolean, nick: string, channels: Channels}) {
this.host = host;
this.port = port
? port
: tlsEnabled
? 6697
: 6667;
this.tlsEnabled = tlsEnabled;
this.nick = nick;
this.channels = channels;
this.client = this.tlsEnabled
? new tls.TLSSocket(new net.Socket())
: new net.Socket();
[...]
this.client.on('close', () => {
logMessage('INFO', this.host, `Connection to ${host} closed`);
try {
setTimeout(() => this.connect(), 60000);
} catch (err) {
logMessage('INFO', this.host, `Failed to reconnect to ${this.host}`);
}
});
this.connect();
}
connect() {
this.client.connect({host: this.host, port: this.port});
}
虽然这对非TLS连接非常有效,并且可以根据需要多次尝试重新连接,而不会创建太多事件侦听器,但对于TLS连接,它甚至不会尝试连接,如果我的配置中只有一个TLS连接,应用程序会立即干净地退出。
我偶然发现
this answer
这看起来很相似,但我还没有找到一点运气,弄清楚如何让它在我的案例和节点中真正起作用。js TLS文档也没有带来启发。
It says this
对于
socket
选择
tls.connect()
:
socket <stream.Duplex>
在给定的套接字上建立安全连接,而不是创建新的套接字。通常,这是一个
net.Socket
,但任何
Duplex
流是允许的。如果指定了此选项,
path
,
host
和
port
被忽略,证书验证除外。通常,一个套接字在传递到时已经连接
tls。连接()
,但可以稍后再连接。连接/断开/破坏
插座
是用户的责任;使命感
tls。连接()
不会导致
net.connect()
被称为。
我再次更新了连接代码,如下所示:
constructor({host, port, tlsEnabled, nick, channels}: {host: string, port: number, tlsEnabled: boolean, nick: string, channels: Channels}) {
this.host = host;
this.port = port
? port
: tlsEnabled
? 6697
: 6667;
this.tlsEnabled = tlsEnabled;
this.nick = nick;
this.channels = channels;
this.client = new net.Socket();
[...]
this.connect();
}
connect() {
if (this.tlsEnabled) {
tls.connect({
socket: this.client,
})
}
this.client.connect({host: this.host, port: this.port});
}
但很明显我做错了,因为我最终
Error: read ECONNRESET
我的应用程序和IRC服务器出错
ngircd
说
SSL protocol error: SSL_accept (error:1408F10B:SSL routines:ssl3_get_record:wrong version number)
.
怎么样
tls。连接()
当你通过一个现有的插座时,它还能工作吗?