Porty diagnostyczne

Ten artykuł dotyczy: ✔️ .NET Core 3.1 i nowszych wersji

Środowisko uruchomieniowe platformy .NET uwidacznia punkt końcowy usługi, który umożliwia innym procesom wysyłanie poleceń diagnostycznych i odbieranie odpowiedzi za pośrednictwem kanału IPC. Ten punkt końcowy jest nazywany portem diagnostycznym. Polecenia można wysyłać do portu diagnostycznego do:

  • Przechwyć zrzut pamięci.
  • Uruchom ślad EventPipe .
  • Zażądaj wiersza polecenia użytego do uruchomienia aplikacji.

Port diagnostyczny obsługuje różne transporty w zależności od platformy. Obecnie implementacje środowiska uruchomieniowego CoreCLR i Mono używają nazwanych potoków w systemach Windows i Unix Domain Sockets w systemach Linux i macOS. Implementacja środowiska uruchomieniowego Mono w systemach Android, iOS i tvOS używa protokołu TCP/IP. Kanał używa niestandardowego protokołu binarnego. Większość deweloperów nigdy nie będzie bezpośrednio korzystać z bazowego kanału i protokołu, ale raczej będzie używać graficznego interfejsu użytkownika lub narzędzi interfejsu wiersza polecenia, które komunikują się w ich imieniu. Na przykład narzędzia dotnet-dump i dotnet-trace abstrakcji wysyłają polecenia protokołu w celu przechwytywania zrzutów i uruchamiania śladów. W przypadku deweloperów, którzy chcą pisać niestandardowe narzędzia, pakiet NuGet Microsoft.Diagnostics.NETCore.Client zapewnia abstrakcję podstawowego transportu i protokołu interfejsu API platformy .NET.

Zagadnienia dotyczące zabezpieczeń

Port diagnostyczny uwidacznia poufne informacje o uruchomionej aplikacji. Jeśli niezaufany użytkownik uzyska dostęp do tego kanału, może obserwować szczegółowy stan programu, w tym wszelkie wpisy tajne w pamięci i dowolnie modyfikować wykonywanie programu. W środowisku uruchomieniowym CoreCLR domyślny port diagnostyczny jest skonfigurowany tak, aby był dostępny tylko przez to samo konto użytkownika, które uruchomiło aplikację lub przez konto z uprawnieniami administratora. Jeśli model zabezpieczeń nie ufa innym procesom z tymi samymi poświadczeniami konta użytkownika, możesz wyłączyć wszystkie porty diagnostyczne, ustawiając zmienną środowiskową DOTNET_EnableDiagnostics=0. To ustawienie zablokuje możliwość korzystania z narzędzi zewnętrznych, takich jak debugowanie platformy .NET lub dowolne z narzędzi diagnostycznych dotnet-*.

Uwaga

Program .NET 6 standardizuje prefiks DOTNET_ zamiast COMPlus_ zmiennych środowiskowych, które konfigurują zachowanie czasu wykonywania platformy .NET. COMPlus_ Jednak prefiks będzie nadal działać. Jeśli używasz poprzedniej wersji środowiska uruchomieniowego platformy .NET, nadal należy użyć prefiksu COMPlus_ dla zmiennych środowiskowych.

Domyślny port diagnostyczny

W systemach Windows, Linux i macOS środowisko uruchomieniowe ma domyślnie otwarty jeden port diagnostyczny w dobrze znanym punkcie końcowym. Jest to port, z którego narzędzia diagnostyczne dotnet-* łączą się automatycznie, gdy nie zostały jawnie skonfigurowane do korzystania z alternatywnego portu. Punkt końcowy to:

  • Windows — nazwany potok \\.\pipe\dotnet-diagnostic-{pid}
  • Linux i macOS — gniazdo domeny systemu Unix {temp}/dotnet-diagnostic-{pid}-{disambiguation_key}-socket

{pid} jest identyfikatorem procesu zapisanym w dziesiętnym, {temp} jest zmienną TMPDIR środowiskową lub wartością /tmp , jeśli TMPDIR jest niezdefiniowana/pusta, i {disambiguation_key} jest czasem rozpoczęcia procesu zapisanym w przecinku. W systemach macOS i NetBSD czas rozpoczęcia procesu to liczba sekund od czasu system UNIX epoki. Na wszystkich innych platformach jest to jiffies od czasu rozruchu.

Wstrzymywanie środowiska uruchomieniowego podczas uruchamiania

Domyślnie środowisko uruchomieniowe wykonuje kod zarządzany natychmiast po uruchomieniu, niezależnie od tego, czy jakiekolwiek narzędzia diagnostyczne nawiązały połączenie z portem diagnostycznym. Czasami warto poczekać na uruchomienie kodu zarządzanego przez środowisko uruchomieniowe do momentu połączenia narzędzia diagnostycznego w celu obserwowania początkowego zachowania programu. Ustawienie zmiennej środowiskowej DOTNET_DefaultDiagnosticPortSuspend=1 powoduje, że środowisko uruchomieniowe czeka, aż narzędzie połączy się z domyślnym portem. Jeśli żadne narzędzie nie jest dołączone po kilku sekundach, środowisko uruchomieniowe wyświetli komunikat ostrzegawczy do konsoli z informacją, że nadal czeka na dołączenie narzędzia.

Konfigurowanie dodatkowych portów diagnostycznych

Uwaga

Działa to tylko w przypadku aplikacji z programem .NET 5 lub nowszym.

Środowiska uruchomieniowe Mono i CoreCLR mogą używać niestandardowych skonfigurowanych portów diagnostycznych w connect roli. Mono obsługuje również niestandardowe porty TCP/IP w listen roli, gdy są używane z dotnet-dsrouter w systemie Android lub iOS. Te porty niestandardowe są dodatkiem do portu domyślnego, który pozostaje dostępny. Istnieje kilka typowych powodów, dla których przydatne są porty niestandardowe:

  • W systemach Android, iOS i tvOS nie ma portu domyślnego, dlatego skonfigurowanie portu jest niezbędne do korzystania z narzędzi diagnostycznych.
  • W środowiskach z kontenerami lub zaporami możesz skonfigurować przewidywalny adres punktu końcowego, który nie różni się w zależności od identyfikatora procesu, jak port domyślny. Następnie można jawnie dodać port niestandardowy do listy dozwolonych lub przekierować go przez niektóre granice zabezpieczeń.
  • W przypadku narzędzi do monitorowania przydatne jest nasłuchiwanie narzędzia w punkcie końcowym, a środowisko uruchomieniowe aktywnie próbuje nawiązać z nim połączenie. Pozwala to uniknąć konieczności ciągłego sondowania nowych aplikacji za pomocą narzędzia do monitorowania. W środowiskach, w których domyślny port diagnostyczny jest niedostępny, należy również unikać konfigurowania monitora z niestandardowym punktem końcowym dla każdej monitorowanej aplikacji.

W każdym kanale komunikacyjnym między narzędziem diagnostycznym a środowiskiem uruchomieniowym platformy .NET jedna strona musi być odbiornikiem i poczekać na nawiązanie połączenia po drugiej stronie. Środowisko uruchomieniowe można skonfigurować do działania w connect roli dla dowolnego portu. (Środowisko uruchomieniowe Mono można również skonfigurować do działania w listen roli dla dowolnego portu). Porty można również niezależnie skonfigurować do wstrzymania podczas uruchamiania, czekając na uruchomienie narzędzia diagnostycznego w celu wydania polecenia wznawiania. Porty skonfigurowane do nawiązywania połączenia powtarzają próby połączenia przez czas nieokreślony, jeśli zdalny punkt końcowy nie nasłuchuje lub jeśli połączenie zostanie utracone. Jednak aplikacja nie zawiesza automatycznie kodu zarządzanego podczas oczekiwania na nawiązanie tego połączenia. Jeśli chcesz, aby aplikacja czekała na nawiązanie połączenia, użyj opcji wstrzymania podczas uruchamiania.

Porty niestandardowe są konfigurowane przy użyciu zmiennej środowiskowej DOTNET_DiagnosticPorts . Ta zmienna powinna być ustawiona na rozdzielaną średnikami listę opisów portów. Każdy opis portu składa się z adresu punktu końcowego i opcjonalnych modyfikatorów, które kontrolują rolę lub listen rolę środowiska uruchomieniowego connect i jeśli środowisko uruchomieniowe powinno zostać zawieszone podczas uruchamiania. W systemie Windows adres punktu końcowego jest nazwą nazwanego potoku bez prefiksu \\.\pipe\ . W systemach Linux i macOS jest to pełna ścieżka do gniazda domeny systemu Unix. W systemach Android, iOS i tvOS adres jest adresem IP i portem. Na przykład:

  1. DOTNET_DiagnosticPorts=my_diag_port1 - (Windows) Środowisko uruchomieniowe łączy się z nazwanym potokiem \\.\pipe\my_diag_port1.
  2. DOTNET_DiagnosticPorts=/foo/tool1.socket;foo/tool2.socket - (Linux i macOS) Środowisko uruchomieniowe łączy się zarówno z gniazdami /foo/tool1.socket domeny systemu Unix, jak i /foo/tool2.socket.
  3. DOTNET_DiagnosticPorts=127.0.0.1:9000 - (Android, iOS i tvOS) Środowisko uruchomieniowe nawiązuje połączenie z adresem IP 127.0.0.1 na porcie 9000.
  4. DOTNET_DiagnosticPorts=/foo/tool1.socket,nosuspend — (Linux i macOS) Ten przykład zawiera nosuspend modyfikator. Środowisko uruchomieniowe próbuje nawiązać połączenie z gniazdem /foo/tool1.socket domeny systemu Unix utworzonym przez narzędzie zewnętrzne. Dodatkowe porty diagnostyczne zwykle powodują, że środowisko uruchomieniowe zawiesza się podczas uruchamiania oczekujące na wznowienie polecenia, ale nosuspend powoduje, że środowisko uruchomieniowe nie czeka.

Pełną składnią portu jest address[,(listen|connect)][,(suspend|nosuspend)]. connectjest wartością domyślną, jeśli nie określono ani listen nie connect jest określona (i listen jest obsługiwana tylko przez środowisko uruchomieniowe Mono w systemie Android lub iOS). suspend jest wartością domyślną, jeśli żadna z nich suspend nie jest określona lub nosuspend nie jest określona.

Użycie w narzędziach diagnostycznych dotnet

Narzędzia, takie jak dotnet-dump, dotnet-counters i dotnet-trace, obsługują lub monitorcollect zlecenia komunikujące się z aplikacją platformy .NET za pośrednictwem portu diagnostycznego.

  • Gdy te narzędzia używają argumentu --processId , narzędzie automatycznie oblicza domyślny adres portu diagnostycznego i nawiązuje z nim połączenie.
  • Podczas określania argumentu --diagnostic-port narzędzie nasłuchuje na danym adresie i należy użyć zmiennej środowiskowej DOTNET_DiagnosticPorts do skonfigurowania aplikacji w celu nawiązania połączenia. Pełny przykład z licznikami dotnet-counter można znaleźć w temacie Using the Diagnostic Port (Korzystanie z portu diagnostycznego).

Używanie routera ds-router do serwera proxy portu diagnostycznego

Wszystkie narzędzia diagnostyczne dotnet-* oczekują połączenia z portem diagnostycznym, który jest lokalnym nazwanym potokiem lub gniazdem domeny systemu Unix. Mono często działa na izolowanym sprzęcie lub w emulatorach, które wymagają serwera proxy za pośrednictwem protokołu TCP, aby stać się dostępne. Narzędzie dotnet-dsrouter może proxy lokalnego nazwanego potoku lub gniazda domeny systemu Unix do protokołu TCP, dzięki czemu narzędzia mogą być używane w tych środowiskach. Aby uzyskać więcej informacji, zobacz dotnet-dsrouter.