診斷連接埠

本文適用於:✔️ .NET Core 3.1 與更新版本

.NET 執行階段可公開服務端點,允許其他處理序傳送診斷命令,並透過 IPC 通道接收回應。 此端點稱為「診斷連接埠」。 命令可以傳送至診斷連接埠,以:

  • 擷取記憶體傾印。
  • 啟動 EventPipe 追蹤。
  • 要求用於啟動該應用程式的命令列。

診斷連接埠視平台之不同,支援不同的傳輸。 CoreCLR 和 Mono Runtime 實作目前在 Windows 上使用具名管道,而在 Linux 和 macOS 上使用 Unix 網域通訊端。 在 Android、iOS 和 tvOS 上的 Mono Runtime 實作,使用 TCP/IP。 該通道使用自訂二進位通訊協定。 大部分的開發人員永遠都不會直接與基礎通道和通訊協定進行互動,而是會使用代表其進行通訊的 GUI 或 CLI 工具。 例如,dotnet-dumpdotnet-trace 工具,會抽象化的傳送通訊協定命令,來擷取傾印以及啟動追蹤。 對於想要撰寫自訂工具的開發人員來說,Microsoft.Diagnostics.NETCore.Client NuGet 套件可提供基礎傳輸和通訊協定的 .NET API 抽象化。

安全性考量

診斷連接埠會公開執行中應用程式的敏感性資訊。 如果不受信任的使用者取得了此通道的存取權,他們即可觀察詳細的程式狀態,包括記憶體中的任何祕密,並可任意修改程式的執行。 CoreCLR Runtime 上的預設診斷連接埠,設定為只能由啟動該應用程式的相同使用者帳戶,或具有進階使用者權限的帳戶存取。 如果安全性模型不信任具有相同使用者帳戶認證的其他處理序,您可以藉由設定環境變數 DOTNET_EnableDiagnostics=0 來停用所有診斷連接埠。 這項設定會讓您無法使用外部工具,例如 .NET 偵錯或任何 dotnet-* 診斷工具。

注意

.NET 6 會針對設定 .NET Runtime 行為的環境變數,透過前置詞 DOTNET_ (而非 COMPlus_) 進行標準化。 不過,COMPlus_ 前置詞將繼續運作。 如果使用舊版的 .NET 執行階段,則您仍應對環境變數使用 COMPlus_ 前置詞。

預設診斷連接埠

在 Windows、Linux 和 macOS 上,執行時間預設會在已知端點開啟一個診斷連接埠。 這是 dotnet-* 診斷工具在未明確地設定為使用替代連接埠時,會自動連線的連接埠。 端點為:

  • Windows - 具名管道 \\.\pipe\dotnet-diagnostic-{pid}
  • Linux 和 macOS - Unix 網域通訊端 {temp}/dotnet-diagnostic-{pid}-{disambiguation_key}-socket

{pid} 是以十進位撰寫的處理序識別碼,{temp}TMPDIR 環境變數或為值 /tmp (如果未定義 TMPDIR 或其為空白),{disambiguation_key} 則是以十進位撰寫的處理序開始時間。 在 macOS 和 NetBSD 上,處理序開始時間是自 UNIX epoch 以來的秒數。 而在所有其他平台上,則是自啟動時間起即為 jiffies。

在啟動時暫停執行階段

根據預設,不論任何診斷工具是否已連線到診斷連接埠,執行階段都會在啟動時立即執行受控程式碼。 有時候,很適合讓執行階段等到連線診斷工具之後,再執行受控程式碼以觀察初始程式行為。 設定環境變數 DOTNET_DefaultDiagnosticPortSuspend=1 可讓執行階段等到工具連線至預設連接埠為止。 如果幾秒後未附加任何工具,執行階段就會將警告訊息列印在主控台上,表示它仍在等待要附加工具。

設定其他診斷連接埠

注意

這僅適用於執行 .NET 5 或更新版本的應用程式。

Mono 和 CoreCLR 執行階段都可以在 connect 角色中使用自訂設定的診斷連接埠。 Mono 在 Android 或 iOS 上搭配 dotnet-dsrouter 使用時,也支援 listen 角色中的自訂 TCP/IP 連接埠。 除了仍可使用預設連接埠之外,還有這些自訂連接埠。 自訂連接埠很有用的幾個常見原因:

  • 在 Android、iOS 和 tvOS 上沒有預設連接埠,因此必須設定連接埠才能使用診斷工具。
  • 在有容器或防火牆的環境中,建議您設定一個可預測的端點位址,其不會像預設連接埠一樣,隨著處理序識別碼而更動。 然後,可以將自訂連接埠明確地新增至允許清單,或跨一些安全性界限,進行 Proxy 處理。
  • 對於監視工具來說,讓工具接聽端點,而且讓執行階段主動嘗試連線到端點,會相當實用。 如此可避免需要監視工具來持續輪詢是否啟動了新的應用程式。 在無法存取預設診斷連接埠的環境中,它也同時避免掉需要對每個受監視的應用程式,為監視器設定自訂端點的作業。

在診斷工具和 .NET 執行階段之間的每個通道,一端必須是接聽程式,等候另一端的連線。 執行階段可以設定為以任何連接埠的 connect 角色執行動作。 (Mono 執行階段也可以設定為以任何連接埠的 listen 角色執行動作。)連接埠也可以獨立設定為在啟動時先暫停,等待診斷工具發出繼續的命令。 如果遠端端端點未接聽或連線遺失,設定為連線的連接埠會無限期地重複其連線嘗試。 但是應用程式在等候建立該連線時,不會自動暫止受控程式碼。 如果希望應用程式等候建立連線,請使用 [啟動時暫停] 選項。

自訂連接埠使用 DOTNET_DiagnosticPorts 環境變數加以設定。 此變數應設定為以分號分隔的連接埠描述清單。 每個連接埠描述都包含一個端點位址和選擇性的修飾元,可控制執行階段的 connectlisten 角色,以及啟動時是否應暫止該執行階段。 在 Windows 上,端點位址是沒有 \\.\pipe\ 前置詞的具名管道名稱。 在 Linux 和 macOS 上,其會是 Unix 網域通訊端的完整路徑。 在 Android、iOS 和 tvOS 上,該位址是 IP 和連接埠。 例如:

  1. DOTNET_DiagnosticPorts=my_diag_port1 - (Windows) 連線到具名管道 \\.\pipe\my_diag_port1 的執行階段。
  2. DOTNET_DiagnosticPorts=/foo/tool1.socket;foo/tool2.socket - (Linux 和 macOS) 同時連線到 Unix 網域通訊端 /foo/tool1.socket/foo/tool2.socket 的執行階段。
  3. DOTNET_DiagnosticPorts=127.0.0.1:9000 - (Android、iOS 和 tvOS) 連線到連接埠 9000 上 IP 127.0.0.1 的執行階段。
  4. DOTNET_DiagnosticPorts=/foo/tool1.socket,nosuspend - (Linux 和 macOS) 此範例有 nosuspend 修飾元。 執行階段會嘗試連線到外部工具所建立的 Unix 網域通訊端 /foo/tool1.socket。 其他診斷連接埠一般會讓該執行階段在啟動時先暫停,以等候繼續的命令,但 nosuspend 會讓該執行階段不等候。

連接埠的完整語法為 address[,(listen|connect)][,(suspend|nosuspend)]。 如果皆未指定 connectlisten,則 connect 為預設值 (且 listen 僅受 Android 或 iOS 上 Mono 執行階段的支援)。 如果未指定 suspendnosuspend,則預設值為 suspend

dotnet 診斷工具中的用法

dotnet-dumpdotnet-countersdotnet-trace 等工具,都支援 collectmonitor 動詞,其透過診斷連接埠與 .NET 應用程式進行通訊。

  • 當這些工具使用 --processId 引數時,此工具會自動計算預設診斷連接埠的位址,並連線該連接埠。
  • 指定 --diagnostic-port 引數時,工具會接聽指定的位址,而您應使用 DOTNET_DiagnosticPorts 環境變數,來設定您的應用程式進行連線。 如需 dotnet-counters 的完整範例,請參閱使用診斷連接埠

使用 ds-router 來 Proxy 診斷連接埠

所有 dotnet-* 診斷工具都應該要連線到是本機具名管道或是 Unix 網域通訊端的診斷連接埠。 Mono 通常由獨立的硬體執行,或在需要透過 TCP 執行 Proxy 的模擬器中執行,才能變成可存取。 dotnet-dsrouter 工具可以將本機具名管道或 Unix 網域通訊端 Proxy 到 TCP,以讓這些環境內可以使用這些工具。 如需詳細資訊,請參閱 dotnet new