windows-remote-desktop-connection-doctor

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Windows Remote Desktop Connection Doctor

Windows远程桌面连接诊断指南

Diagnose and fix Windows App (AVD/WVD/W365) connection quality issues on macOS, with focus on transport protocol optimization.
在macOS上诊断并修复Windows App(AVD/WVD/W365)的连接质量问题,重点优化传输协议。

Background

背景知识

Azure Virtual Desktop transport priority: UDP Shortpath > TCP > WebSocket. UDP Shortpath provides the best experience (lowest latency, supports UDP Multicast). When it fails, the client falls back to WebSocket over TCP 443 through the gateway, adding significant latency overhead.
Azure Virtual Desktop传输协议优先级:UDP Shortpath > TCP > WebSocket。UDP Shortpath能提供最佳体验(延迟最低,支持UDP Multicast)。当UDP Shortpath连接失败时,客户端会回退到通过网关使用TCP 443的WebSocket协议,这会大幅增加延迟开销。

Diagnostic Workflow

诊断流程

Step 1: Collect Connection Info

步骤1:收集连接信息

Ask the user to provide the Connection Info from Windows App (click the signal icon in the toolbar). Key fields to extract:
FieldWhat It Tells
Transport ProtocolCurrent transport:
UDP
,
UDP Multicast
,
WebSocket
, or
TCP
Round-Trip Time (RTT)End-to-end latency in ms
Available BandwidthCurrent bandwidth in Mbps
GatewayThe AVD gateway hostname and port
Service RegionAzure region code (e.g., SEAS = South East Asia)
If Transport Protocol is
UDP
or
UDP Multicast
, the connection is optimal — no further diagnosis needed.
If Transport Protocol is
WebSocket
or
TCP
, proceed to Step 2.
请用户提供Windows App中的连接信息(点击工具栏中的信号图标)。需要提取的关键字段:
字段说明
传输协议当前使用的传输协议:
UDP
UDP Multicast
WebSocket
TCP
往返延迟(RTT)端到端延迟,单位为毫秒
可用带宽当前带宽,单位为Mbps
网关AVD网关的主机名和端口
服务区域Azure区域代码(例如:SEAS = 东南亚)
如果传输协议为
UDP
UDP Multicast
,则连接状态最优,无需进一步诊断。
如果传输协议为
WebSocket
TCP
,请继续执行步骤2。

Step 2: Collect Network Evidence

步骤2:收集网络证据

Gather evidence in parallel — do NOT make assumptions. Run the following checks simultaneously:
并行收集证据——请勿主观假设。同时执行以下检查:

2A: Network Interfaces and Routing

2A: 网络接口与路由

bash
ifconfig | grep -E "^[a-z]|inet |utun"
netstat -rn | head -40
scutil --proxy
Look for:
  • utun interfaces: Identify VPN/proxy TUN tunnels (ShadowRocket, Clash, Tailscale)
  • Default route priority: Which interface handles default traffic
  • Split routing:
    0/1 + 128.0/1 → utun
    pattern means a VPN captures all traffic
  • System proxy: HTTP/HTTPS proxy enabled on localhost ports
bash
ifconfig | grep -E "^[a-z]|inet |utun"
netstat -rn | head -40
scutil --proxy
需要排查以下内容:
  • utun接口:识别VPN/代理的TUN隧道(如ShadowRocket、Clash、Tailscale)
  • 默认路由优先级:哪个接口处理默认流量
  • 拆分路由
    0/1 + 128.0/1 → utun
    模式表示VPN捕获所有流量
  • 系统代理:是否在本地端口启用了HTTP/HTTPS代理

2B: RDP Client Process and Connections

2B: RDP客户端进程与连接

bash
undefined
bash
undefined

Find the Windows App process (NOT "msrdc" — the new client uses "Windows" as process name)

查找Windows App进程(注意:不是"msrdc"——新版客户端进程名为"Windows")

ps aux | grep -i -E 'msrdc|Windows' | grep -v grep
ps aux | grep -i -E 'msrdc|Windows' | grep -v grep

Check its network connections

检查其网络连接

lsof -i -n -P 2>/dev/null | grep -i "Windows" | head -20
lsof -i -n -P 2>/dev/null | grep -i "Windows" | head -20

Check for UDP connections

检查UDP连接

lsof -i UDP -n -P 2>/dev/null | head -30

Key evidence to look for:
- **Source IP `198.18.0.x`**: Traffic is being routed through ShadowRocket/proxy TUN tunnel
- **No UDP connections from Windows process**: Shortpath not established
- **Only TCP 443**: Fallback to gateway WebSocket transport
lsof -i UDP -n -P 2>/dev/null | head -30

需要重点关注的证据:
- **源IP为`198.18.0.x`**:流量被路由至ShadowRocket/代理的TUN隧道
- **Windows进程无UDP连接**:Shortpath未建立
- **仅存在TCP 443连接**:回退到网关的WebSocket传输协议

2C: VPN/Proxy State

2C: VPN/代理状态

bash
undefined
bash
undefined

Environment proxy variables

环境代理变量

env | grep -i proxy
env | grep -i proxy

System proxy via scutil

通过scutil查看系统代理

scutil --proxy
scutil --proxy

ShadowRocket config API (if accessible on local network)

ShadowRocket配置API(若可在本地网络访问)

NO_PROXY="<local-ip>" curl -s --connect-timeout 5 "http://<local-ip>:8080/api/read"
undefined
NO_PROXY="<local-ip>" curl -s --connect-timeout 5 "http://<local-ip>:8080/api/read"
undefined

2D: Tailscale State (if running)

2D: Tailscale状态(若已运行)

bash
tailscale status
tailscale netcheck
The
netcheck
output reveals NAT type (
MappingVariesByDestIP
), UDP support, and public IP — valuable even when Tailscale is not the problem.
bash
tailscale status
tailscale netcheck
netcheck
输出会显示NAT类型(
MappingVariesByDestIP
)、UDP支持情况和公网IP——即使Tailscale不是问题根源,这些信息也很有价值。

Step 3: Analyze Windows App Logs

步骤3:分析Windows App日志

This is the most critical step. Windows App logs contain transport negotiation details that no network-level test can reveal.
Log location on macOS:
~/Library/Containers/com.microsoft.rdc.macos/Data/Library/Logs/Windows App/
Files are named:
com.microsoft.rdc.macos_v<version>_<date>_<time>.log
See references/windows_app_log_analysis.md for detailed log parsing guidance.
这是最关键的步骤。Windows App日志包含了网络层面测试无法获取的传输协商细节。
macOS上的日志位置:
~/Library/Containers/com.microsoft.rdc.macos/Data/Library/Logs/Windows App/
日志文件命名格式:
com.microsoft.rdc.macos_v<version>_<date>_<time>.log
详细的日志解析指南请参考references/windows_app_log_analysis.md

Quick Log Search

快速日志搜索

bash
LOG_DIR=~/Library/Containers/com.microsoft.rdc.macos/Data/Library/Logs/Windows\ App
bash
LOG_DIR=~/Library/Containers/com.microsoft.rdc.macos/Data/Library/Logs/Windows\ App

Find the most recent log

查找最新的日志

LATEST_LOG=$(ls -t "$LOG_DIR"/*.log 2>/dev/null | head -1)
LATEST_LOG=$(ls -t "$LOG_DIR"/*.log 2>/dev/null | head -1)

Search for transport-critical entries (filter out noise)

搜索与传输相关的关键条目(过滤无关内容)

grep -i -E "STUN|TURN|VPN|Routed|Shortpath|FetchClient|clientoption|GATEWAY.*ERR|Certificate.*valid|InternetConnectivity|Passed URL" "$LATEST_LOG" | grep -v "BasicStateManagement|DynVC|dynvcstat|asynctransport"
undefined
grep -i -E "STUN|TURN|VPN|Routed|Shortpath|FetchClient|clientoption|GATEWAY.*ERR|Certificate.*valid|InternetConnectivity|Passed URL" "$LATEST_LOG" | grep -v "BasicStateManagement|DynVC|dynvcstat|asynctransport"
undefined

Key Log Patterns

关键日志模式

Log PatternMeaning
Passed: InternetConnectivity
Health check completed successfully
TCP/IP Traffic Routed Through VPN: No/Yes
Client detected VPN routing for TCP
STUN/TURN Traffic Routed Through VPN: Yes
Client detected VPN routing for STUN/TURN
Passed URL: https://...wvd.microsoft.com/ Response Time: Nms
Gateway reachability confirmed
FetchClientOptions exception: Request timed out
Critical: Client cannot get transport options from gateway
Certificate validation failed
TLS interception or DNS poisoning detected
OnRDWebRTCRedirectorRpc rtcSession not handled
WebRTC session setup not handled by client
日志模式含义
Passed: InternetConnectivity
网络连通性健康检查通过
TCP/IP Traffic Routed Through VPN: No/Yes
客户端检测到TCP流量是否通过VPN路由
STUN/TURN Traffic Routed Through VPN: Yes
客户端检测到STUN/TURN流量通过VPN路由
Passed URL: https://...wvd.microsoft.com/ Response Time: Nms
网关可达性验证通过
FetchClientOptions exception: Request timed out
严重问题:客户端无法从网关获取传输选项
Certificate validation failed
检测到TLS拦截或DNS投毒
OnRDWebRTCRedirectorRpc rtcSession not handled
客户端未处理WebRTC会话建立请求

Compare Working vs Broken Logs

对比正常与异常日志

When possible, compare a log from when the connection worked (UDP) with the current log:
bash
undefined
若有可能,将连接正常(使用UDP)时的日志与当前日志进行对比:
bash
undefined

Compare startup health check blocks

对比启动阶段的健康检查模块

for f in "$LOG_DIR"/*.log; do echo "=== $(basename "$f") ===" grep -E "InternetConnectivity|Routed Through VPN|Passed URL|FetchClient" "$f" | head -10 echo "" done

A working log will contain the full health check block (InternetConnectivity, VPN routing detection, gateway URL tests). A broken log may show these entries missing entirely, or show certificate/timeout errors instead.
for f in "$LOG_DIR"/*.log; do echo "=== $(basename "$f") ===" grep -E "InternetConnectivity|Routed Through VPN|Passed URL|FetchClient" "$f" | head -10 echo "" done

正常日志会包含完整的健康检查模块(网络连通性、VPN路由检测、网关URL测试)。异常日志可能完全缺失这些条目,或显示证书错误/超时错误。

Step 4: Determine Root Cause

步骤4:确定根本原因

Based on collected evidence, identify the root cause category:
根据收集到的证据,确定根本原因类别:

Category A: VPN/Proxy Interference

类别A:VPN/代理干扰

Evidence: Windows App source IP is
198.18.0.x
, STUN/TURN routed through VPN, no UDP connections.
Fix: Add DIRECT rules for AVD traffic in the proxy tool:
DOMAIN-SUFFIX,wvd.microsoft.com,DIRECT
DOMAIN-SUFFIX,microsoft.com,DIRECT
IP-CIDR,13.104.0.0/14,DIRECT
Verify: Temporarily disable VPN/proxy, reconnect VDI, check if transport changes to UDP.
证据:Windows App的源IP为
198.18.0.x
,STUN/TURN流量通过VPN路由,无UDP连接。
修复方案:在代理工具中为AVD流量添加DIRECT规则:
DOMAIN-SUFFIX,wvd.microsoft.com,DIRECT
DOMAIN-SUFFIX,microsoft.com,DIRECT
IP-CIDR,13.104.0.0/14,DIRECT
验证:临时禁用VPN/代理,重新连接VDI,检查传输协议是否切换为UDP。

Category B: ISP/Network UDP Restriction

类别B:ISP/网络UDP限制

Evidence: Even with all VPNs off, still WebSocket. No UDP connections.
FetchClientOptions
timeout.
Verify:
bash
undefined
证据:即使关闭所有VPN,仍使用WebSocket协议,无UDP连接,
FetchClientOptions
超时。
验证
bash
undefined

Test STUN connectivity to a known server

测试与已知STUN服务器的连通性

python3 -c " import socket, struct, os header = struct.pack('!HHI', 0x0001, 0, 0x2112A442) + os.urandom(12) for srv in [('stun.l.google.com', 19302), ('stun1.l.google.com', 19302)]: try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.settimeout(3) s.sendto(header, srv) data, addr = s.recvfrom(1024) print(f'STUN from {srv[0]}: OK') s.close(); break except: print(f'STUN from {srv[0]}: FAILED'); s.close() "

**Fix options**:
- Try mobile hotspot (isolate home network from ISP)
- Check router NAT type (Full Cone NAT preferred)
- Enable UPnP on router
- Try IPv6 if available
- Contact ISP about UDP restrictions
python3 -c " import socket, struct, os header = struct.pack('!HHI', 0x0001, 0, 0x2112A442) + os.urandom(12) for srv in [('stun.l.google.com', 19302), ('stun1.l.google.com', 19302)]: try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.settimeout(3) s.sendto(header, srv) data, addr = s.recvfrom(1024) print(f'STUN from {srv[0]}: OK') s.close(); break except: print(f'STUN from {srv[0]}: FAILED'); s.close() "

**修复选项**:
- 尝试使用移动热点(将家庭网络与ISP隔离)
- 检查路由器NAT类型(优先选择Full Cone NAT)
- 在路由器上启用UPnP
- 若可用,尝试使用IPv6
- 联系ISP咨询UDP限制问题

Category C: Client Health Check Failure

类别C:客户端健康检查失败

Evidence: Log shows certificate validation errors at startup, health check block (InternetConnectivity, STUN/TURN detection) missing from log,
FetchClientOptions
timeout.
This means the client cannot complete its diagnostic/capability discovery, preventing Shortpath negotiation.
Possible causes:
  • ISP HTTPS interception/MITM (especially in China)
  • DNS poisoning returning incorrect IPs for Microsoft diagnostic endpoints
  • Firewall blocking Microsoft telemetry endpoints
Fix options:
  • Change DNS to 8.8.8.8 or 1.1.1.1 (bypass ISP DNS)
  • Route Microsoft traffic through a clean proxy
  • Check if ISP injects certificates
证据:日志显示启动阶段证书验证错误,健康检查模块(网络连通性、STUN/TURN检测)缺失,
FetchClientOptions
超时。
这意味着客户端无法完成诊断/能力发现,从而无法进行Shortpath协商。
可能原因
  • ISP的HTTPS拦截/中间人攻击(在中国尤为常见)
  • DNS投毒导致Microsoft诊断端点返回错误IP
  • 防火墙阻止了Microsoft遥测端点
修复选项
  • 将DNS改为8.8.8.8或1.1.1.1(绕过ISP DNS)
  • 通过干净的代理路由Microsoft流量
  • 检查ISP是否注入了证书

Category D: Server-Side Shortpath Not Enabled

类别D:服务器端未启用Shortpath

Evidence: Log shows no STUN/TURN or Shortpath related entries at all (not even detection), but health checks pass and no errors.
This means the AVD host pool does not have RDP Shortpath enabled. This requires admin action on the Azure portal.
证据:日志中完全没有STUN/TURN或Shortpath相关条目(甚至未检测到),但健康检查通过且无错误。
这意味着AVD主机池未启用RDP Shortpath,需要管理员在Azure门户中进行配置。

Step 5: Verify Fix

步骤5:验证修复效果

After applying a fix, reconnect the VDI session and verify:
  1. Check Connection Info — Transport Protocol should show
    UDP
    or
    UDP Multicast
  2. RTT should drop significantly (e.g., from 165ms to 40-60ms)
  3. Verify with lsof:
bash
lsof -i UDP -n -P 2>/dev/null | grep -i "Windows"
应用修复方案后,重新连接VDI会话并验证:
  1. 查看连接信息——传输协议应显示为
    UDP
    UDP Multicast
  2. RTT应显著降低(例如从165ms降至40-60ms)
  3. 使用lsof验证:
bash
lsof -i UDP -n -P 2>/dev/null | grep -i "Windows"

Should show UDP connections if Shortpath is active

若Shortpath已激活,应显示UDP连接

undefined
undefined

References

参考资料

  • references/windows_app_log_analysis.md — Detailed log parsing patterns, error signatures, and comparison methodology
  • references/avd_transport_protocols.md — How AVD transport selection works, STUN/TURN/ICE overview, Shortpath architecture
  • references/windows_app_log_analysis.md — 详细的日志解析模式、错误特征和对比方法
  • references/avd_transport_protocols.md — AVD传输协议选择机制、STUN/TURN/ICE概述、Shortpath架构