如何在C#中实现PsPing TCP ping

15

我正在尝试使用C#实现Mark Russinovich的SysInternals PsPing工具,以使用TCP ping测量延迟。

我不确定它如何进行ping调用(显然不使用原始窗口套接字,因为它不需要管理员特权来运行)。我知道hping会发送SYN数据包并测量响应时间。

用于准确测量服务器延迟的实现技术是什么?对于仅测量包确认的网络延迟(而非页面加载时间)的TCP,是否有相应库可用?

C:\>psping stackoverflow.com:80

PsPing v2.01 - PsPing - ping, latency, bandwidth measurement utility
Copyright (C) 2012-2014 Mark Russinovich
Sysinternals - www.sysinternals.com

Pinging 198.252.206.16 with 32 bytes of data:
5 iterations (warmup 1) ping test:
Reply from 198.252.206.16: 81.57ms
Reply from 198.252.206.16: 80.81ms
Reply from 198.252.206.16: 80.68ms
Reply from 198.252.206.16: 80.52ms
Reply from 198.252.206.16: 80.71ms

Ping statistics for 198.252.206.16:
  Sent = 4, Received = 4, Lost = 0 (0% loss),
  Minimum = 80.52ms, Maximum = 80.81ms, Average = 80.68ms

更新:请不要回答类似于“为什么不使用Ping类,它已经完成了这个任务”的问题,因为我正在询问TCP上的ping,而不是ICMP。


1
许多Sysinternals工具使用未记录的系统调用。你不太可能找到一个易于参考的来源来说明它是如何做到的,更不用说如何从C#中实现相同的功能了。 - Scott Chamberlain
@ScottChamberlain 我只是在尝试,也许有一种我不知道的方法。 - ahmet alp balkan
@ahmetalpbalkan:Ping类如何?它使您能够ping服务器或内部IP,并且您可以获得回复时间吗?http://msdn.microsoft.com/en-us/library/system.net.networkinformation.ping%28v=vs.110%29.aspx - houssam
1
@houssam 兄弟,我已经到处写了“TCP” ping。Ping类使用ICMP。 - ahmet alp balkan
1
psping stackoverflow.com 会生成 ICMP 流量。你应该使用 psping stackoverflow.com:80 来测试 TCP 连通性。 - ziya
@MaxwellTroyMiltonKing 哦,对了。已经编辑过了。 - ahmet alp balkan
3个回答

30

我尝试了几种方法,一开始认为必须使用原始套接字或至少使用本地调用,但是一个简单的TCP连接和关闭似乎会产生与psping实用程序完全相同的结果:

var times = new List<double>();
for (int i = 0; i < 4; i++)
{
    var sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    sock.Blocking = true;

    var stopwatch = new Stopwatch();

    // Measure the Connect call only
    stopwatch.Start();
    sock.Connect(endPoint);
    stopwatch.Stop();

    double t = stopwatch.Elapsed.TotalMilliseconds;
    Console.WriteLine("{0:0.00}ms", t);
    times.Add(t);

    sock.Close();

    Thread.Sleep(1000);
}
Console.WriteLine("{0:0.00} {1:0.00} {2:0.00}", times.Min(), times.Max(), times.Average());

通过使用Wireshark检查流量,我可以确认psping和上面的代码片段正在创建完全相同的数据包序列。

-> [SYN]
<- [SYN,ACK]
-> [ACK]
-> [FIN,ACK]
<- [FIN,ACK]
-> [ACK]

使用TCP ping,没有预热,从psping输出:

C:\>psping -w 0 stackoverflow.com:80

PsPing v2.01 - PsPing - ping, latency, bandwidth measurement utility
Copyright (C) 2012-2014 Mark Russinovich
Sysinternals - www.sysinternals.com

TCP connect to 198.252.206.16:80:
4 iterations (warmup 0) connecting test:
Connecting to 198.252.206.16:80: 92.30ms
Connecting to 198.252.206.16:80: 83.16ms
Connecting to 198.252.206.16:80: 83.29ms
Connecting to 198.252.206.16:80: 82.98ms

TCP connect statistics for 198.252.206.16:80:
  Sent = 4, Received = 4, Lost = 0 (0% loss),
  Minimum = 82.98ms, Maximum = 92.30ms, Average = 85.43ms

程序的输出结果如下:
C:\>TcpPing.exe stackoverflow.com 80
88.60ms
83.65ms
84.05ms
84.05ms
83.65 88.60 85.09

就测量而言,不得不说,有时在不同的运行中会得到相当多不同的结果,但整体来看它们似乎非常接近:这证明测量Connect()调用已经足够好了。我想,取几百个结果的中位数可能会更加可靠。


1
对我来说非常有效!它也反映了与 psping 非常接近的结果。非常感谢,实至名归。 - ahmet alp balkan
3
EndPoint类有点难以操作,所以我更喜欢使用IPAddress类并指定端口。要实现这个目的,可以按照以下方式进行操作:
  1. 获取IP地址:IPAddress ip = Dns.GetHostEntry("www.google.com.au").AddressList[0];
  2. 指定端口号:int port = 443;
  3. 通过socket连接IP地址和端口号:sock.Connect(ip, port);
- Dave Lucre

2
Winsock可以轻松地让您实现这一点。
你是否查看过像http://www.elifulkerson.com/projects/tcping.php这样的程序源代码?
这是一个相当简单的控制台程序,可以做到你想要的(据我所知),并提供了非常清晰、简短和易于阅读的源代码(即使对于非C++程序员,我已经有一段时间没有练习C++了,尽管如此,我发现它非常好读)。
您可以使用VS构建和调试它,以快速找到所需的几个Win32 API调用。这样,您肯定可以轻松将有趣的部分转换为C#或嵌入到托管DLL中。
在进行操作之前,请确保它确实实现了你所需要的功能。
源链接:http://www.elifulkerson.com/projects/downloads/tcping-0.23/tcping-src.zip

0

我已经将上述的tcpping.exePsPing.exe进行了比较。 PsPing.exe的输出结果非常接近于Windows的ping.exe,而tcpping.exe的输出结果则差异很大。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接