Xamarin.Mac中Ping.SendPingAsync获取的往返时间与终端结果不符的问题排查及解决方案咨询
解决Xamarin.Mac中Ping.SendPingAsync返回延迟偏高的问题
我之前在做Xamarin.Mac项目时也遇到过一模一样的问题——用.NET的Ping.SendPingAsync拿到的往返时间总是比终端的ping命令慢不少,Windows上却完全正常。结合你的环境(Xamarin.Mac 6.20.2、.NET Framework 4.8、Mono 6.12.0.93、macOS Catalina 10.15.2),咱们来一步步解决这个问题:
问题根源
这个差异主要来自Mono对Ping API的macOS实现:.NET的Ping类在macOS上是基于Mono的封装,底层调用系统API时会额外引入线程调度、对象初始化的开销;而终端的ping是原生系统工具,直接和网络栈交互,效率更高,所以延迟结果更准确。
解决方案
方案1:调用系统原生ping命令并解析输出(推荐,和终端结果完全一致)
既然终端的ping结果是准确的,我们可以直接在代码里调用系统的ping命令,捕获输出后解析出往返时间。这种方式完全绕过Mono的Ping封装,结果和你在终端看到的完全一致。
示例代码:
private async Task NativePingAsync() { for (int i = 0; i < 100; i++) { try { // macOS的ping命令:-c 1 表示发送1个包,-W 1表示超时1秒(单位秒) var processStartInfo = new ProcessStartInfo { FileName = "/sbin/ping", Arguments = "-c 1 -W 1 google.com", RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true }; using (var process = Process.Start(processStartInfo)) { await process.WaitForExitAsync(); var output = await process.StandardOutput.ReadToEndAsync(); // 解析输出中的time值,比如匹配 "time=54.082 ms" 这样的字符串 var match = System.Text.RegularExpressions.Regex.Match(output, @"time=(\d+\.\d+) ms"); if (match.Success) { if (double.TryParse(match.Groups[1].Value, out var roundtripTime)) { Console.WriteLine($"RoundTrip time: {roundtripTime} ms"); } } else { Console.WriteLine("Failed to get ping details"); } } } catch (Exception ex) { Console.WriteLine($"Ping failed: {ex.Message}"); } await Task.Delay(1000); } }
方案2:优化现有Ping.SendPingAsync的使用(减少部分延迟)
如果不想调用系统命令,可以优化现有代码——你当前每次循环都新建Ping对象,这会带来额外的初始化开销。复用同一个Ping实例能减少这部分延迟,让结果更接近终端值:
示例代码:
private async Task OptimizedPingAsync() { // 把Ping实例移到循环外面,复用 using (var ping = new Ping()) { for (int i = 0; i < 100; i++) { try { PingReply reply = await ping.SendPingAsync("google.com", 500); if (reply.Status == IPStatus.Success) { Console.WriteLine("Address: {0}", reply.Address.ToString()); Console.WriteLine("RoundTrip time: {0}", reply.RoundtripTime); } else { Console.WriteLine("Failed to get ping details"); } } catch (Exception ex) { Console.WriteLine($"Ping failed: {ex.Message}"); } await Task.Delay(1000); } } }
效果说明
- 方案1的结果会和你在终端执行
ping google.com的结果完全一致,因为用的是同一个原生工具; - 方案2能减少大约10-15ms的额外开销,但可能还是会和终端有微小差距,毕竟还是基于Mono的封装。
内容的提问来源于stack exchange,提问作者Mr.Tin Tin
相关产品推荐
相关产品推荐

