How to implement PsPing TCP ping in C#
Asked Answered
T

3

16

I am trying to implement Mark Russinovich's SysInternals PsPing tool in C# to measure latencies using TCP ping.

I am not sure how it makes the ping call (apparently not uses raw Window sockets, because it does not require Administrator privileges to run). I know hping sends SYN packet over TCP and measures response time.

What would be the implementation technique for accurate measurement of server latency which over TCP does not measure page load times but just the network latency for the package acknowledgement? Is there a library for this?

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

Update: Please don't answer like "why don't you use Ping class, it already does the thing" as I'm asking about ping over TCP, not ICMP.

Teacart answered 26/9, 2014 at 19:55 Comment(6)
A lot of the Sysinternals tools are using undocumented system calls. You are unlikely to find a easy to reference source saying how it does it, let alone how to do the same from C#.Antiparticle
@ScottChamberlain just trying out perhaps there's a method that I don't know of.Teacart
@ahmetalpbalkan : what about Ping class that enables you to ping a server or internal IP and you can get the replay Time ? msdn.microsoft.com/en-us/library/…Idiocrasy
@Idiocrasy dude I wrote "TCP" ping all over. Ping class uses ICMP.Teacart
psping stackoverflow.com is generating ICMP traffic. You should use psping stackoverflow.com:80 for TCP.Lobelia
@MaxwellTroyMiltonKing ah, right. edited.Teacart
L
31

I have tried several approaches, first thinking I had to use raw sockets or at least use native calls, but a simple TCP connect and close seems to create exactly the same results as the psping utility:

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());

Inspecting the traffic using Wireshark, I can confirm both psping and the snippet above are creating exactly the same sequence of packets.

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

Output from psping with no warm-up and using TCP ping:

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

Output from the program above:

C:\>TcpPing.exe stackoverflow.com 80
88.60ms
83.65ms
84.05ms
84.05ms
83.65 88.60 85.09

As for measurements, I must say, sometimes there are quite a few different results at different runs, but overall they seemed pretty close: kind of proves measuring the Connect() call is good enough. I'm thinking, taking a median of a few hundred results might prove it with a bit more confidence.

Lobelia answered 5/10, 2014 at 8:38 Comment(2)
Worked out very well for me! It also reflects very close results to psping. Thank you very much, well deserved.Teacart
The EndPoint class is a bit unwieldy, so I prefer to use the IPAddress class and specify a port. To do that: IPAddress ip = Dns.GetHostEntry("www.google.com.au").AddressList[0]; int port = 443; and then sock.Connect(ip, port);Balbinder
P
2

Winsock will certainly allow you to do this easily.

Did you look at source of programs like http://www.elifulkerson.com/projects/tcping.php ?

Pretty straightforward program (console) which does exactly what you want (AFAIK), and provided with source code which looks like to be very clear, short and easy to read (even for non c++ programmers, I didn't practice C++ since a while and despite it I found it very nice to read).

You can build it and debug it with VS to quickly find what you want. It should be easy to get there the few Win32 API calls involved in TCP Ping. This way, you can certainly easily convert the interesting part to C# or embed it in a managed DLL.

Just test before if it does exactly what you want.

Source link : http://www.elifulkerson.com/projects/downloads/tcping-0.23/tcping-src.zip

Parceling answered 2/10, 2014 at 7:21 Comment(0)
B
0

I have compared the above tcpping.exe with PsPing.exe. The output result of PsPing.exe is very close to ping.exe of windows, and the output of tcpping.exe varies widely.

Boyla answered 4/3, 2020 at 17:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.