本文適用於:✔️ .NET Core 3.1 及更新版本
.NET 執行階段可公開服務端點,允許其他處理序傳送診斷命令,並透過 IPC 通道接收回應。 此端點稱為「診斷連接埠」。 命令可以傳送至診斷連接埠,以:
- 擷取記憶體傾印。
- 啟動 EventPipe 追蹤。
- 要求用於啟動該應用程式的命令列。
診斷埠依平台支援不同的傳輸方式。 目前 CoreCLR 與 Mono 執行時實作皆在 Windows 上使用命名管線,Linux 與 macOS 則使用 Unix 網域套接字。 Android、iOS 和 tvOS 上的 Mono 執行時實作使用 TCP/IP。 該頻道使用 自訂的二進位協定。 大多數開發者不會直接與底層通道和協定互動,而是會使用代表他們的 GUI 或 CLI 工具來溝通。 例如,dotnet-dump 和 dotnet-trace 工具將傳送協定指令進行抽象化,以便擷取傾印並啟動追蹤。 對於想撰寫自訂工具的開發者, Microsoft.Diagnostics.NETCore.Client NuGet 套件 提供了底層傳輸與協定的 .NET API 抽象化。
安全性考慮
診斷埠會揭露關於執行中的應用程式的敏感資訊。 若不信任使用者取得此通道存取權,他們可觀察詳細的程式狀態,包括記憶體中的秘密,並任意修改程式執行方式。 在 CoreCLR 執行時,預設的診斷埠被設定為只有啟動應用程式的同一使用者帳號或擁有超級使用者權限的帳號才能存取。 如果你的安全模型不信任擁有相同使用者帳號憑證的其他程序,你可以透過設定環境變數 DOTNET_EnableDiagnostics=0來停用所有診斷埠。 這個設定會阻擋你使用外部工具,例如 .NET 除錯或任何 dotnet-* 診斷工具。
預設診斷埠
在 Windows、Linux 和 macOS 上,執行時預設會開啟一個診斷埠,且該埠位於知名端點。 這是 dotnet-* 診斷工具在未明確設定使用替代埠時自動連接的埠口。 終點為:
- Windows - 命名管線
\\.\pipe\dotnet-diagnostic-{pid} - Linux 與 macOS - Unix 域通訊插座
{temp}/dotnet-diagnostic-{pid}-{disambiguation_key}-socket
{pid}是以十進位寫入的程序 ID,{temp}是TMPDIR環境變數或若/tmp為未定義/為空的值TMPDIR,則{disambiguation_key}是以十進位表示的程序開始時間。 在 macOS 和 NetBSD 上,程序開始時間是自 UNIX 時代起的秒數。 在其他所有平台上,這是自開機以來的 jiffies。
啟動時暫停執行時間
預設情況下,執行時一開始就會執行受管程式碼,不論是否有診斷工具連接到該診斷埠。 有時候讓執行時等到診斷工具連接後才執行受管程式碼,觀察程式初期行為會很有用。 設定環境變數 DOTNET_DefaultDiagnosticPortSuspend=1 會讓執行時等待工具連接到預設埠。 如果幾秒後都沒有工具連接,執行時會向控制台印出警告訊息,說明它還在等待工具連接。
設定額外的診斷埠
備註
這只適用於執行 .NET 5 或更新版本的應用程式。
Mono 與 CoreCLR 運行環境皆可使用在 connect 角色中的自訂設定診斷埠。 Mono 也支援在 Android 或 iOS 上與 listen 搭配使用時,在此角色中自訂 TCP/IP 埠。 這些自訂端口是在預設端口仍然可用的情況下額外新增的。 自訂埠口有幾個常見的實用原因:
- 在 Android、iOS 和 tvOS 上沒有預設埠口,因此必須設定埠口才能使用診斷工具。
- 在有容器或防火牆的環境中,你可能想設定一個可預測的端點位址,且不會像預設埠口那樣隨程序 ID 變化。 接著,該自訂端口可以明確加入允許名單,或通過某種安全邊界代理。
- 對於監控工具來說,讓工具在端點上監聽,並執行時主動嘗試連接該端點是很有用的。 這樣就不用監控工具不斷輪詢新應用程式的啟動。 在無法存取預設診斷埠的環境中,也能避免為每個被監控應用程式設定自訂端點。
在診斷工具與 .NET 執行環境之間的每個通訊通道中,一方必須擔任監聽者,並等待另一端連線。 執行時可設定為在任何埠口扮演該 connect 角色。 (Mono 運行環境也可以設定為擔任任何端口的 listen 角色。)端口也可以獨立設定在啟動時暫停,等待診斷工具發出恢復命令。 設定為連接的埠口如果遠端端點不聽或連線中斷,會無限重複連線嘗試。 但應用程式不會在等待建立連線時自動暫停受管理程式碼。 如果你想讓應用程式等待連線建立,可以使用啟動時暫停的選項。
自訂埠口是透過 DOTNET_DiagnosticPorts 環境變數來設定的。 此變數應設為以分號分隔的埠描述清單。 每個埠描述包含一個端點位址和可選修飾符,這些修飾符控制執行時的connect或listen角色,以及執行時在啟動時是否應暫停。 在 Windows 上,端點位址是命名管線名稱,但沒有前 \\.\pipe\ 綴。 在 Linux 和 macOS 上,這是通往 Unix 網域 socket 的完整路徑。 在 Android、iOS 和 tvOS 上,位址是 IP 和埠口。 例如:
-
DOTNET_DiagnosticPorts=my_diag_port1- (Windows) 執行時連接至命名管線\\.\pipe\my_diag_port1。 -
DOTNET_DiagnosticPorts=/foo/tool1.socket;foo/tool2.socket- (Linux 與 macOS)執行時同時連接 Unix 網域 socket/foo/tool1.socket與/foo/tool2.socket。 -
DOTNET_DiagnosticPorts=127.0.0.1:9000- (Android、iOS 及 tvOS)執行時連接 IP 127.0.0.1,埠號為 9000。 -
DOTNET_DiagnosticPorts=/foo/tool1.socket,nosuspend- (Linux 與 macOS)此範例有nosuspend修飾符。 執行時會嘗試連接到外部工具所建立的 Unix Domain Socket/foo/tool1.socket。 額外的診斷埠通常會在啟動時讓執行時暫停等待恢復指令,但nosuspend會導致執行時不會等待。
埠的完整語法為 address[,(listen|connect)][,(suspend|nosuspend)]。 如果未指定 connect 或 listen,則 connect 為預設值(而 listen 僅在 Android 或 iOS 上的 Mono 執行環境中受支援)。
suspend 若未 suspend 指定 或 nosuspend ,則為預設值。
dotnet 診斷工具中的應用
例如 dotnet-dump、dotnet-counters 和 dotnet-trace 等工具都支援使用 collect 或 monitor 動詞,透過診斷埠與 .NET 應用程式溝通。
- 當這些工具使用
--processId參數時,工具會自動計算預設的診斷埠位址並連接到該位址。 - 在指定
--diagnostic-port參數時,工具會監聽給定的位址,你應該用DOTNET_DiagnosticPorts環境變數來設定你的應用程式連線。 如需完整的 dotnet 計數器範例,請參見 「使用診斷埠」。
使用 ds-router 來代理診斷埠
所有 dotnet-* 診斷工具都預期會連接到本地命名管道或 Unix 域套接字的診斷埠。 Mono 通常在孤立的硬體或需要透過 TCP 代理才能被存取的模擬器中運行。 dotnet-dsrouter 工具可以代理本地的命名管道或 Unix 網域套接字到 TCP,使這些工具能在這些環境中使用。 欲了解更多資訊,請參閱 dotnet-dsrouter。