我正在编写基于 TypeScript 的 nodejs TLS 客户端,以支持使用 pfx
证书安全连接到服务器。它作为 NestJS 服务运行和注入。从连接开始几毫秒后(在获得第一个响应后),我遇到了服务器断开连接 (FIN + ACK
) 的问题。
我的客户代码:
import {
Injectable,
Logger,
OnApplicationBootstrap,
OnModuleInit,
UnauthorizedException,
} from '@nestjs/common';
import { RcpEntity } from '@modules/rcp/domain/entities/rcp.entity';
import * as tls from 'tls';
import * as fs from 'fs';
import { ConnectionOptions, TLSSocket } from 'tls';
import { ConfigService } from '@nestjs/config';
import { join } from 'path';
import { RcpRepository } from '@modules/rcp/database/rcp.repository';
@Injectable()
export class RcpClientService implements OnModuleInit {
tlsSocket : TLSSocket;
logger = new Logger('rcp-client');
pfx: Buffer;
constructor(
private readonly rcpRepository: RcpRepository,
private readonly configService: ConfigService,
) {
// this.rcpsConnections = {};
}
private tlsOptions = (rcp: RcpEntity): ConnectionOptions => {
return {
host: rcp.host,
port: rcp.port,
passphrase: this.configService.get<string>('SSL_PASSPHRASE'),
pfx: this.pfx,
enableTrace: false,
// requestCert: true,
rejectUnauthorized: false,
timeout: 1000000,
sessionTimeout: 10000,
checkServerIdentity: () => { return null; },
};
}
onModuleInit() {
this.connectAllRcps();
}
private async connectAllRcps(): Promise<void> {
// Only one server is configured in this example
const rcps = await this.rcpRepository.findMany();
if (rcps.length == 0) {
this.logger.warn('No RcpServers was added to rcp table');
return;
}
this.pfx = fs.readFileSync(
join(__dirname, '../src/infrasctructure/pfx/ssl-server-cert.pfx')
);
await Promise.all(
rcps.map(async (rcp) => {
this.logger.debug('RcpClient connecting to: ' + rcp.host + ':' + rcp.port + ', timeout: ' + rcp.timeout);
this.tlsSocket = tls.connect(
this.tlsOptions(rcp),
async () => {
process.stdin.pipe(this.tlsSocket);
process.stdin.resume();
// this request gets to server
this.sendOrderToRcp(rcp.id.value, "25,001");
await this.delay(100);
// this not
this.sendOrderToRcp(rcp.id.value, "25,001");
});
this.tlsSocket.setNoDelay(true);
this.tlsSocket.setKeepAlive(true, 0);
this.tlsSocket.setTimeout(0, async function () {
console.log('timeout');
});
this.tlsSocket.setEncoding('utf8');
this.tlsSocket.on("data", (data) => { this._onReceiveData(data, rcp.id.value, rcp.name) });
this.tlsSocket.on("error", (data) => { this._onError(data, rcp.id.value, rcp.name) });
this.tlsSocket.on("end", (data) => { this._onEnd(data, rcp.id.value, rcp.name) });
this.tlsSocket.on("close", function () {
console.error("close");
});
}),
);
}
delay(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
private async _onReceiveData(data: string, rcpid: string, rcpname: string) {
this.logger.debug('(rcpId:' + rcpid + '): Received: ' + data);
}
private async _onError(data: string, rcpid: string, rcpname: string) {
this.logger.error('(rcpId:' + rcpid + '): Error: ' + data);
}
private async _onEnd(data: string, rcpid: string, rcpname: string) {
this.logger.debug('(rcpId:' + rcpid + '): End connection, data: ' + data);
}
private async sendOrderToRcp(rcpId: string, order: string): Promise<void> {
if (!this.tlsSocket) {
throw new UnauthorizedException('Rcp server connection unauthorized');
}
this.logger.debug('Sending command: ' + order + ' to RCPID: ' + rcpId);
this.tlsSocket.write(order, (data) => {
console.log(data);
});
}
}
服务器日志:
[backend] [Nest] 118 - 06/23/2021, 8:43:26 AM [NestApplication] Nest application successfully started +5ms
[backend] [Nest] 118 - 06/23/2021, 8:43:26 AM [rcp-client] RcpClient connecting to: 150.153.100.82:13000, timeout: 30000
[backend] [Nest] 118 - 06/23/2021, 8:43:26 AM [rcp-client] Sending command: 25,001 to RCPID: a3750a03-2572-44dc-95c5-1bbbeeefe067
[backend] undefined
[backend] [Nest] 118 - 06/23/2021, 8:43:26 AM [rcp-client] (rcpId:a3750a03-2572-44dc-95c5-1bbbeeefe067): Received: 25,001,1,2,0
[backend] [Nest] 118 - 06/23/2021, 8:43:26 AM [rcp-client] (rcpId:a3750a03-2572-44dc-95c5-1bbbeeefe067): End connection, data: undefined
[backend] close
[backend] [Nest] 118 - 06/23/2021, 8:43:26 AM [rcp-client] Sending command: 25,001 to RCPID: a3750a03-2572-44dc-95c5-1bbbeeefe067
[backend] Error: This socket has been ended by the other party
[backend] at TLSSocket.writeAfterFIN [as write] (node:net:448:14)
[backend] at RcpClientService.sendOrderToRcp (/usr/app/dist/main.js:2378:24)
[backend] at TLSSocket.<anonymous> (/usr/app/dist/main.js:2345:22) {
[backend] code: 'EPIPE'
[backend] }
我的猜测 我的猜测是客户端以某种方式终止了在wireshark 日志中显示的套接字。 我想知道是否
process.stdin.pipe(this.tlsSocket);
process.stdin.resume();
正在以某种方式终止连接?这个管道究竟是如何在这里工作的