NodeJS TLS 客户端连接在第一次收到请求后关闭

时间:2021-06-23 08:59:34

标签: node.js typescript ssl nestjs

我正在编写基于 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 日志: enter image description here

我的猜测 我的猜测是客户端以某种方式终止了在wireshark 日志中显示的套接字。 我想知道是否

              process.stdin.pipe(this.tlsSocket);
              process.stdin.resume();

正在以某种方式终止连接?这个管道究竟是如何在这里工作的

0 个答案:

没有答案