windows-remote-desktop-connection-doctor
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWindows 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:
| Field | What It Tells |
|---|---|
| Transport Protocol | Current transport: |
| Round-Trip Time (RTT) | End-to-end latency in ms |
| Available Bandwidth | Current bandwidth in Mbps |
| Gateway | The AVD gateway hostname and port |
| Service Region | Azure region code (e.g., SEAS = South East Asia) |
If Transport Protocol is or , the connection is optimal — no further diagnosis needed.
UDPUDP MulticastIf Transport Protocol is or , proceed to Step 2.
WebSocketTCP请用户提供Windows App中的连接信息(点击工具栏中的信号图标)。需要提取的关键字段:
| 字段 | 说明 |
|---|---|
| 传输协议 | 当前使用的传输协议: |
| 往返延迟(RTT) | 端到端延迟,单位为毫秒 |
| 可用带宽 | 当前带宽,单位为Mbps |
| 网关 | AVD网关的主机名和端口 |
| 服务区域 | Azure区域代码(例如:SEAS = 东南亚) |
如果传输协议为或,则连接状态最优,无需进一步诊断。
UDPUDP Multicast如果传输协议为或,请继续执行步骤2。
WebSocketTCPStep 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 --proxyLook for:
- utun interfaces: Identify VPN/proxy TUN tunnels (ShadowRocket, Clash, Tailscale)
- Default route priority: Which interface handles default traffic
- Split routing: pattern means a VPN captures all traffic
0/1 + 128.0/1 → utun - 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)
- 默认路由优先级:哪个接口处理默认流量
- 拆分路由:模式表示VPN捕获所有流量
0/1 + 128.0/1 → utun - 系统代理:是否在本地端口启用了HTTP/HTTPS代理
2B: RDP Client Process and Connections
2B: RDP客户端进程与连接
bash
undefinedbash
undefinedFind 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 transportlsof -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
undefinedbash
undefinedEnvironment 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"
undefinedNO_PROXY="<local-ip>" curl -s --connect-timeout 5 "http://<local-ip>:8080/api/read"
undefined2D: Tailscale State (if running)
2D: Tailscale状态(若已运行)
bash
tailscale status
tailscale netcheckThe output reveals NAT type (), UDP support, and public IP — valuable even when Tailscale is not the problem.
netcheckMappingVariesByDestIPbash
tailscale status
tailscale netchecknetcheckMappingVariesByDestIPStep 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>.logSee 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\ Appbash
LOG_DIR=~/Library/Containers/com.microsoft.rdc.macos/Data/Library/Logs/Windows\ AppFind 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"
undefinedgrep -i -E "STUN|TURN|VPN|Routed|Shortpath|FetchClient|clientoption|GATEWAY.*ERR|Certificate.*valid|InternetConnectivity|Passed URL" "$LATEST_LOG" | grep -v "BasicStateManagement|DynVC|dynvcstat|asynctransport"
undefinedKey Log Patterns
关键日志模式
| Log Pattern | Meaning |
|---|---|
| Health check completed successfully |
| Client detected VPN routing for TCP |
| Client detected VPN routing for STUN/TURN |
| Gateway reachability confirmed |
| Critical: Client cannot get transport options from gateway |
| TLS interception or DNS poisoning detected |
| WebRTC session setup not handled by client |
| 日志模式 | 含义 |
|---|---|
| 网络连通性健康检查通过 |
| 客户端检测到TCP流量是否通过VPN路由 |
| 客户端检测到STUN/TURN流量通过VPN路由 |
| 网关可达性验证通过 |
| 严重问题:客户端无法从网关获取传输选项 |
| 检测到TLS拦截或DNS投毒 |
| 客户端未处理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
undefinedCompare 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 , STUN/TURN routed through VPN, no UDP connections.
198.18.0.xFix: 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,DIRECTVerify: Temporarily disable VPN/proxy, reconnect VDI, check if transport changes to UDP.
证据:Windows App的源IP为,STUN/TURN流量通过VPN路由,无UDP连接。
198.18.0.x修复方案:在代理工具中为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. timeout.
FetchClientOptionsVerify:
bash
undefined证据:即使关闭所有VPN,仍使用WebSocket协议,无UDP连接,超时。
FetchClientOptions验证:
bash
undefinedTest 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 restrictionspython3 -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, timeout.
FetchClientOptionsThis 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:
- Check Connection Info — Transport Protocol should show or
UDPUDP Multicast - RTT should drop significantly (e.g., from 165ms to 40-60ms)
- Verify with lsof:
bash
lsof -i UDP -n -P 2>/dev/null | grep -i "Windows"应用修复方案后,重新连接VDI会话并验证:
- 查看连接信息——传输协议应显示为或
UDPUDP Multicast - RTT应显著降低(例如从165ms降至40-60ms)
- 使用lsof验证:
bash
lsof -i UDP -n -P 2>/dev/null | grep -i "Windows"Should show UDP connections if Shortpath is active
若Shortpath已激活,应显示UDP连接
undefinedundefinedReferences
参考资料
- 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架构