Compartir por


Puertos de diagnóstico

Este artículo se aplica a: ✔️ .NET Core 3.1 y versiones posteriores

El entorno de ejecución de .NET expone un punto de conexión de servicio que permite a otros procesos enviar comandos de diagnóstico y recibir respuestas mediante un canal IPC. Este punto de conexión se denomina puerto de diagnóstico. Se pueden enviar comandos a un puerto de diagnóstico con estos fines:

  • Capturar un volcado de memoria.
  • Iniciar un seguimiento de EventPipe.
  • Solicitar la línea de comandos usada para iniciar la aplicación.

El puerto de diagnóstico admite diferentes transportes en función de la plataforma. Actualmente, las implementaciones de CoreCLR y el entorno de ejecución Mono usan canalizaciones con nombre en sockets de dominio de Windows y UNIX en Linux y macOS. La implementación del entorno de ejecución Mono en Android, iOS y tvOS usa TCP/IP. El canal usa un protocolo binario personalizado. La mayoría de los desarrolladores nunca interactuarán directamente con el canal y el protocolo subyacentes, sino que usarán las herramientas de GUI o CLI que se comunican en su nombre. Por ejemplo, las herramientas dotnet-dump y dotnet-trace abstraen los comandos de protocolo de envío para capturar volcados de memoria e iniciar seguimientos. Los desarrolladores que quieran escribir herramientas personalizadas disponen del paquete NuGet Microsoft.Diagnsotics.NETCore.Client, que proporciona una abstracción de la API de .NET del transporte y el protocolo subyacentes.

Consideraciones sobre la seguridad

El puerto de diagnóstico expone información confidencial sobre una aplicación en ejecución. Si un usuario que no es de confianza accede a este canal, podría ver el estado detallado del programa, incluidos los secretos que están en la memoria, y modificar arbitrariamente la ejecución del programa. En el entorno de ejecución de CoreCLR, el puerto de diagnóstico predeterminado está configurado para que solo esté disponible para la misma cuenta de usuario que haya iniciado la aplicación o para una cuenta con permisos de superusuario. Si el modelo de seguridad no confía en otros procesos con las mismas credenciales de cuenta de usuario, puede deshabilitar todos los puertos de diagnóstico estableciendo la variable de entorno DOTNET_EnableDiagnostics=0. Este valor bloqueará la capacidad de usar herramientas externas, como la depuración de .NET o cualquiera de las herramientas de diagnóstico dotnet-*.

Nota:

.NET 6 estandariza en el prefijo DOTNET_ en lugar de en COMPlus_ para las variables de entorno que configuran el comportamiento en tiempo de ejecución de .NET. Sin embargo, el prefijo COMPlus_ seguirá funcionando. Si usa una versión anterior del runtime de .NET, debe seguir usando el prefijo COMPlus_ para las variables de entorno.

Puerto de diagnóstico predeterminado

En Windows, Linux y macOS, el entorno de ejecución tiene abierto un puerto de diagnóstico de forma predeterminada en un punto de conexión conocido. Este es el puerto al que se conectan automáticamente las herramientas de diagnóstico dotnet-* si no se han configurado explícitamente para que usen un puerto alternativo. El punto de conexión es el siguiente:

  • Windows: canalización con nombre \\.\pipe\dotnet-diagnostic-{pid}
  • Linux y macOS: socket de dominio UNIX {temp}/dotnet-diagnostic-{pid}-{disambiguation_key}-socket

{pid} es el identificador de proceso escrito en decimal; {temp} es la variable de entorno TMPDIR o el valor /tmp si TMPDIR no está definido o vacío, y {disambiguation_key} es la hora de inicio del proceso escrita en decimal. En macOS y NetBSD, la hora de inicio del proceso es el número de segundos desde el tiempo UNIX epoch. En todas las demás plataformas, es jiffies desde el tiempo de arranque.

Suspensión del entorno de ejecución en el inicio

De manera predeterminada, el entorno de ejecución ejecuta el código administrado en cuanto se inicia, independientemente de si las herramientas de diagnóstico se han conectado al puerto de diagnóstico. A veces resulta útil que el entorno de ejecución no ejecute el código administrado hasta después de que se conecte una herramienta de diagnóstico para poder observar el comportamiento inicial del programa. Establecer la variable de entorno DOTNET_DefaultDiagnosticPortSuspend=1 hace que el entorno de ejecución espere hasta que se conecte una herramienta al puerto predeterminado. Si no se conecta ninguna herramienta después de varios segundos, el entorno de ejecución imprime un mensaje de advertencia en la consola en el que se explica que sigue esperando a que se conecte una herramienta.

Configuración de puertos de diagnóstico adicionales

Nota:

Esto solo funciona para las aplicaciones que ejecutan .NET 5 o una versión posterior.

Los entornos de ejecución Mono y CoreCLR pueden usar puertos de diagnóstico configurados personalizados en el rol connect. Mono también admite puertos TCP/IP personalizados en el rol listen, cuando se usa con dotnet-dsrouter en Android o iOS. Estos puertos personalizados son adicionales al puerto predeterminado que sigue estando disponible. Hay algunas razones comunes por las que los puertos personalizados son útiles:

  • En Android, iOS y tvOS no hay ningún puerto predeterminado, por lo que hay que configurar uno para usar las herramientas de diagnóstico.
  • En entornos con contenedores o firewalls, es posible que le interese configurar una dirección de punto de conexión predecible que no varíe en función del id. de proceso, tal como lo hace el puerto predeterminado. A continuación, el puerto personalizado se puede agregar explícitamente a una lista de elementos permitidos o enviarse por proxy mediante algún límite de seguridad.
  • Para las herramientas de supervisión, se recomienda que la herramienta escuche en un punto de conexión y que el entorno de ejecución intente conectarse activamente a ella. Esto evita que se necesite la herramienta de supervisión para sondear continuamente las nuevas aplicaciones que se inician. En entornos en los que no se puede acceder al puerto de diagnóstico predeterminado, también se evita tener que configurar la supervisión con un punto de conexión personalizado para cada aplicación supervisada.

En cada canal de comunicación entre una herramienta de diagnóstico y el entorno de ejecución de .NET, un lado debe ser el cliente de escucha y esperar a que se conecte el otro lado. El tiempo de ejecución se puede configurar para que actúe en el rol connect de cualquier puerto. (El entorno de ejecución Mono también se puede configurar para que actúe en el rol listen de cualquier puerto). Los puertos también se pueden configurar de forma independiente para que se suspendan en el inicio y esperen a que una herramienta de diagnóstico emita un comando de reanudación. Los puertos configurados para conectarse repiten sus intentos de conexión indefinidamente si el punto de conexión remoto no escucha o si se pierde la conexión. Pero la aplicación no suspende automáticamente el código administrado mientras espera a establecer esa conexión. Si quiere que la aplicación espere a que se establezca una conexión, use la opción de suspender en el inicio.

Los puertos personalizados se configuran mediante la variable de entorno DOTNET_DiagnosticPorts. Esta variable debe establecerse en una lista delimitada por punto y coma de descripciones de puertos. Cada descripción de puerto consta de una dirección de punto de conexión y modificadores opcionales que permiten controlar el rol de connect o listen del entorno de ejecución, además de si el entorno de ejecución debe suspenderse en el inicio. En Windows, la dirección de punto de conexión es el nombre de una canalización con nombre sin el prefijo \\.\pipe\. En Linux y macOS, es la ruta de acceso completa a un socket de dominio UNIX. En Android, iOS y tvOS, la dirección es una dirección IP y un puerto. Por ejemplo:

  1. DOTNET_DiagnosticPorts=my_diag_port1 (Windows): el entorno de ejecución se conecta a la canalización con nombre \\.\pipe\my_diag_port1.
  2. DOTNET_DiagnosticPorts=/foo/tool1.socket;foo/tool2.socket (Linux y macOS): el entorno de ejecución se conecta a los sockets de dominio de UNIX /foo/tool1.socket y /foo/tool2.socket.
  3. DOTNET_DiagnosticPorts=127.0.0.1:9000 (Android, iOS y tvOS): el entorno de ejecución se conecta a la IP 127.0.0.1 en el puerto 9000.
  4. DOTNET_DiagnosticPorts=/foo/tool1.socket,nosuspend: (Linux y macOS) este ejemplo tiene el modificador nosuspend. El tiempo de ejecución intenta conectarse al socket de dominio Unix /foo/tool1.socket que crea una herramienta externa. Normalmente, los puertos de diagnóstico adicionales harían que el entorno de ejecución se suspendiera al iniciarse esperando un comando de reanudación, pero nosuspend hace que no espere.

La sintaxis completa para un puerto es address[,(listen|connect)][,(suspend|nosuspend)]. connect es el valor predeterminado si no se especifican connect ni listen (y listen solo es compatible con el entorno de ejecución Mono en Android o iOS). suspend es el valor predeterminado si no se especifican suspend ni nosuspend.

Uso en herramientas de diagnóstico de dotnet

Herramientas como dotnet-dump, dotnet-counters y dotnet-trace admiten verbos collect o monitor que se comunican con una aplicación de .NET mediante el puerto de diagnóstico.

  • Cuando estas herramientas usan el argumento --processId, calculan automáticamente la dirección de puerto de diagnóstico predeterminada y se conectan a ella.
  • Al especificar el argumento --diagnostic-port, las herramientas escuchan en la dirección especificada, y debe usar la variable de entorno DOTNET_DiagnosticPorts para configurar la aplicación y conectarse. Para obtener un ejemplo completo con dotnet-counters, consulte Uso del puerto de diagnóstico.

Uso de ds-router para redirigir mediante proxy el puerto de diagnóstico

Todas las herramientas de diagnóstico dotnet-* esperan conectarse a un puerto de diagnóstico que sea un socket de dominio UNIX o una canalización con nombre local. A menudo, Mono se ejecuta en hardware aislado o en emuladores que necesitan un proxy por TCP para estar disponibles. La herramienta dotnet-dsrouter puede redirigir mediante proxy una canalización con nombre o un socket de dominio de UNIX local hacia TCP para que las herramientas se puedan usar en esos entornos. Para obtener más información, vea dotnet-dsrouter.