使用来自 Lava.Lang.Process 的 Xamarin Ping IP 或主机名
Pinging IP or HOSTNAME with Xamarin from Lava.Lang.Process
我正在尝试这段代码,它 returns 总是 TTL Expired
即使 ip 或主机名是 unreachable
、 timeout
或任何其他不同的问题:
using System.Net.NetworkInformation;
PingReply Reply = await pingo.SendPingAsync(text_ip.Text, 4000, buffer, options);
Toast.MakeText(Activity, Reply.Status.ToString(), ToastLength.Long).Show();
switch (Reply.Status)
{
case IPStatus.Success:
Toast.MakeText(Activity, Reply.Status.ToString(), ToastLength.Long).Show();
break;
case IPStatus.TimedOut:
Toast.MakeText(Activity, Reply.Status.ToString(), ToastLength.Long).Show();
break;
case IPStatus.TimeExceeded:
Toast.MakeText(Activity, Reply.Status.ToString(), ToastLength.Long).Show();
break;
case IPStatus.DestinationHostUnreachable:
Toast.MakeText(Activity, Reply.Status.ToString(), ToastLength.Long).Show();
break;
case IPStatus.DestinationNetworkUnreachable:
Toast.MakeText(Activity, Reply.Status.ToString(), ToastLength.Long).Show();
break;
case IPStatus.DestinationUnreachable:
Toast.MakeText(Activity, Reply.Status.ToString(), ToastLength.Long).Show();
break;
}
我在
https://github.com/mono/mono/blob/master/mcs/class/System/System.Net.NetworkInformation/Ping.cs(第 339 行)
并在 :
https://bugzilla.xamarin.com/show_bug.cgi?id=53284
调用系统ping命令并检查退出码:
if (!ping.WaitForExit (timeout) || (ping.HasExited && ping.ExitCode == 2))
status = IPStatus.TimedOut;
else if (ping.ExitCode == 0)
status = IPStatus.Success;
else if (ping.ExitCode == 1)
status = IPStatus.TtlExpired;
So TTL expired is set when there was no timeout, no error or success (exit code 2 or 0), and the exit code was 1.
If ping does not receive any reply packets at all it will exit with code 1
. If a packet count and deadline are both specified, and fewer than count packets are received by the time the deadline has arrived, it will also exit with code 1
. On other error it exits with code 2
. Otherwise it exits with code 0
. This makes it possible to use the exit code to see if a host is alive or not.
So a return value of 1 indicates that no response has been received (for various reasons) and the Mono implementation sets the TTL expired
status in this case. I would expect that a time out status would be returned in such cases. But it seems that the timeout
detection of the Mono implementation is not triggered here (e.g. because the ping command exits upon on it's own timeout before).
So there is other possible solutions:
To treat a TTL expired
as host not alive (but this will then ignore real TTL expired
detections)
无论如何有人可以展示另一种方法来做到这一点例如:
try
{
Process ipProcess = runtime.exec("ping -c 1 8.8.8.8");
int exitValue = ipProcess.waitFor();
ipProcess.destroy();
if(exitValue == 0)
{
// Success
}
else
{
// Failure
}
}
catch (IOException | InterruptedException e)
{
e.printStackTrace();
}
并从中得到 Time in ms
, Ttl value
, Statistics
, Packet Loss
, Received Packets
, Transmited Packets
等信息每个 ping 序列的进程 shell ?
更新
如何为此目的实施它:
public async void add_data(string adresa)
{
await Task.Delay(ping_interval);
if (sekuenca < sekuenca_db && nderprit == false)
{
try
{
PingReply Reply = await pingo.SendPingAsync(text_ip.Text, timeout, buffer, options);
switch (Reply.Status)
{
case IPStatus.Success:
string sekuena = sekuenca.ToString();
mdata.Add(new data() { titulli = "From : " + Reply.Address.ToString(), sekuenca = "Secuenca : " + sekuena + ",", ttl = "TTL : " + Reply.Options.Ttl.ToString() + ",", madhesia = "Send : " + Reply.Buffer.Length.ToString() + " bytes", koha = "Time : " + Reply.RoundtripTime.ToString() + " ms" });
mAdapter.NotifyItemInserted(mdata.Count() - 1);
if (ndaluar == false)
{
mRecyclerView.ScrollToPosition(mdata.Count() - 1);
}
time = time + Reply.RoundtripTime;
koha.Add(Convert.ToInt32(Reply.RoundtripTime));
add_data(text_ip.Text);
break;
使用 OS' 内置 ping
命令获取 ping 时间的方法是启动一个进程,读取其输出并解析该数据.
因此需要采取的步骤:
- 创建
System.Diagnostics.Process
- 正确设置其 StartInfo-Parameters
- 重定向其标准输出
- 将您可以访问的 StreamReader 的输出读取为字符串
- 解析该字符串。为此,您需要了解结果输出的布局方式
对于第一部分(直到字符串部分),您的代码可能如下所示:
Process P = new Process();
P.StartInfo.FileName = "ping";
P.StartInfo.Arguments = "-c 3 8.8.8.8"; // Take 3 samples to 8.8.8.8
P.StartInfo.UseShellExecute = false;
P.StartInfo.RedirectStandardOutput = true;
string readData = "";
if (P.Start())
readData = P.StandardOutput.ReadToEnd(); // This will also wait for the process to at least close its stdout
Console.Write(readData.ToString()); // Doing this, you will see how the output looks like
在此之后,您将在 readData
中得到如下输出:
64 bytes from 8.8.8.8: icmp_req=1 ttl=46 time=13.9 ms
64 bytes from 8.8.8.8: icmp_req=2 ttl=46 time=13.9 ms
64 bytes from 8.8.8.8: icmp_req=3 ttl=46 time=13.9 ms
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 3016ms
rtt min/avg/max/mdev = 13.910/13.926/13.951/0.010 ms
您现在需要做的就是解析您感兴趣的相关部分。我建议使用 System.Text.RegularExpressions.Regex
来实现这一点。我假设您对平均往返时间感兴趣。在这种情况下,您需要执行以下步骤:
- 忽略除包含统计数据的最后一行以外的所有内容
- 提取您感兴趣的值
如果您需要的值为 float
(或 double
),请解析该值
List<string> Lines = new List<string>(readData.Replace("\r\n", "\n").Split('\n'));
while (Lines.Count > 0 && !Lines[0].StartsWith("---"))
Lines.RemoveAt(0);
// Here, we either have an empty list or a list starting with the line --- 8.8.8.8 ping statistics ---
float avgPingTime = 0;
if (Lines.Count > 2)
{
// Our important line is now Lines[2], the one starting with "rtt"
Match M = Regex.Match(Lines[2], @"^rtt [^0-9]*([\d][^\/]+)\/([^\/]+)\/([^\/]+)\/([^ ]+) ms$");
if (M != null && M.Success) // A match has indeed been found
{
string avgPingString = M.Groups[2].Value;
// Now parse that value
float.TryParse(avgPingString, System.Globalization.NumberStyles.Float, System.Globalization.NumberFormatInfo.InvariantInfo, out avgPingTime);
}
}
if (avgPingTime > 0)
{
// We parsed the value correctly here
}
但是,如果您对统计数据之前的每一行的统计数据感兴趣,则需要一种不同的方法:
64 bytes from 8.8.8.8: icmp_req=2 ttl=46 time=13.9 ms
有 n
行,所有行 在 以 ---
:
开头的行之前
List<string> Lines = new List<string>(readData.Replace("\r\n", "\n").Split('\n'));
while (Lines.Count > 0 && !Lines[0].StartsWith("---"))
{
Match M = Regex.Match(Lines[0], @"^[\d]+ bytes from ([^:]+): [^ ]+ ttl=([\d]+) time=([^ ]+) ms");
if (M != null && M.Success)
{
string IP = M.Groups[1].Value;
string TTL = M.Groups[2].Value;
string timeStr = M.Groups[3].Value;
Console.WriteLine(String.Format("Ping to {0} took {2} ms with a ttl of {1}", IP, TTL, timeStr));
// Parsing the timeStr will work the same way as above
}
Lines.RemoveAt(0);
}
我正在尝试这段代码,它 returns 总是 TTL Expired
即使 ip 或主机名是 unreachable
、 timeout
或任何其他不同的问题:
using System.Net.NetworkInformation;
PingReply Reply = await pingo.SendPingAsync(text_ip.Text, 4000, buffer, options);
Toast.MakeText(Activity, Reply.Status.ToString(), ToastLength.Long).Show();
switch (Reply.Status)
{
case IPStatus.Success:
Toast.MakeText(Activity, Reply.Status.ToString(), ToastLength.Long).Show();
break;
case IPStatus.TimedOut:
Toast.MakeText(Activity, Reply.Status.ToString(), ToastLength.Long).Show();
break;
case IPStatus.TimeExceeded:
Toast.MakeText(Activity, Reply.Status.ToString(), ToastLength.Long).Show();
break;
case IPStatus.DestinationHostUnreachable:
Toast.MakeText(Activity, Reply.Status.ToString(), ToastLength.Long).Show();
break;
case IPStatus.DestinationNetworkUnreachable:
Toast.MakeText(Activity, Reply.Status.ToString(), ToastLength.Long).Show();
break;
case IPStatus.DestinationUnreachable:
Toast.MakeText(Activity, Reply.Status.ToString(), ToastLength.Long).Show();
break;
}
我在 https://github.com/mono/mono/blob/master/mcs/class/System/System.Net.NetworkInformation/Ping.cs(第 339 行)
并在 : https://bugzilla.xamarin.com/show_bug.cgi?id=53284
调用系统ping命令并检查退出码:
if (!ping.WaitForExit (timeout) || (ping.HasExited && ping.ExitCode == 2))
status = IPStatus.TimedOut;
else if (ping.ExitCode == 0)
status = IPStatus.Success;
else if (ping.ExitCode == 1)
status = IPStatus.TtlExpired;
So TTL expired is set when there was no timeout, no error or success (exit code 2 or 0), and the exit code was 1.
If ping does not receive any reply packets at all it will exit with
code 1
. If a packet count and deadline are both specified, and fewer than count packets are received by the time the deadline has arrived, it will also exit withcode 1
. On other error it exits withcode 2
. Otherwise it exits withcode 0
. This makes it possible to use the exit code to see if a host is alive or not.So a return value of 1 indicates that no response has been received (for various reasons) and the Mono implementation sets the
TTL expired
status in this case. I would expect that a time out status would be returned in such cases. But it seems that thetimeout
detection of the Mono implementation is not triggered here (e.g. because the ping command exits upon on it's own timeout before).So there is other possible solutions:
To treat a
TTL expired
as host not alive (but this will then ignore realTTL expired
detections)
无论如何有人可以展示另一种方法来做到这一点例如:
try
{
Process ipProcess = runtime.exec("ping -c 1 8.8.8.8");
int exitValue = ipProcess.waitFor();
ipProcess.destroy();
if(exitValue == 0)
{
// Success
}
else
{
// Failure
}
}
catch (IOException | InterruptedException e)
{
e.printStackTrace();
}
并从中得到 Time in ms
, Ttl value
, Statistics
, Packet Loss
, Received Packets
, Transmited Packets
等信息每个 ping 序列的进程 shell ?
更新
如何为此目的实施它:
public async void add_data(string adresa)
{
await Task.Delay(ping_interval);
if (sekuenca < sekuenca_db && nderprit == false)
{
try
{
PingReply Reply = await pingo.SendPingAsync(text_ip.Text, timeout, buffer, options);
switch (Reply.Status)
{
case IPStatus.Success:
string sekuena = sekuenca.ToString();
mdata.Add(new data() { titulli = "From : " + Reply.Address.ToString(), sekuenca = "Secuenca : " + sekuena + ",", ttl = "TTL : " + Reply.Options.Ttl.ToString() + ",", madhesia = "Send : " + Reply.Buffer.Length.ToString() + " bytes", koha = "Time : " + Reply.RoundtripTime.ToString() + " ms" });
mAdapter.NotifyItemInserted(mdata.Count() - 1);
if (ndaluar == false)
{
mRecyclerView.ScrollToPosition(mdata.Count() - 1);
}
time = time + Reply.RoundtripTime;
koha.Add(Convert.ToInt32(Reply.RoundtripTime));
add_data(text_ip.Text);
break;
使用 OS' 内置 ping
命令获取 ping 时间的方法是启动一个进程,读取其输出并解析该数据.
因此需要采取的步骤:
- 创建
System.Diagnostics.Process
- 正确设置其 StartInfo-Parameters
- 重定向其标准输出
- 将您可以访问的 StreamReader 的输出读取为字符串
- 解析该字符串。为此,您需要了解结果输出的布局方式
对于第一部分(直到字符串部分),您的代码可能如下所示:
Process P = new Process();
P.StartInfo.FileName = "ping";
P.StartInfo.Arguments = "-c 3 8.8.8.8"; // Take 3 samples to 8.8.8.8
P.StartInfo.UseShellExecute = false;
P.StartInfo.RedirectStandardOutput = true;
string readData = "";
if (P.Start())
readData = P.StandardOutput.ReadToEnd(); // This will also wait for the process to at least close its stdout
Console.Write(readData.ToString()); // Doing this, you will see how the output looks like
在此之后,您将在 readData
中得到如下输出:
64 bytes from 8.8.8.8: icmp_req=1 ttl=46 time=13.9 ms
64 bytes from 8.8.8.8: icmp_req=2 ttl=46 time=13.9 ms
64 bytes from 8.8.8.8: icmp_req=3 ttl=46 time=13.9 ms
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 3016ms
rtt min/avg/max/mdev = 13.910/13.926/13.951/0.010 ms
您现在需要做的就是解析您感兴趣的相关部分。我建议使用 System.Text.RegularExpressions.Regex
来实现这一点。我假设您对平均往返时间感兴趣。在这种情况下,您需要执行以下步骤:
- 忽略除包含统计数据的最后一行以外的所有内容
- 提取您感兴趣的值
如果您需要的值为
float
(或double
),请解析该值List<string> Lines = new List<string>(readData.Replace("\r\n", "\n").Split('\n')); while (Lines.Count > 0 && !Lines[0].StartsWith("---")) Lines.RemoveAt(0); // Here, we either have an empty list or a list starting with the line --- 8.8.8.8 ping statistics --- float avgPingTime = 0; if (Lines.Count > 2) { // Our important line is now Lines[2], the one starting with "rtt" Match M = Regex.Match(Lines[2], @"^rtt [^0-9]*([\d][^\/]+)\/([^\/]+)\/([^\/]+)\/([^ ]+) ms$"); if (M != null && M.Success) // A match has indeed been found { string avgPingString = M.Groups[2].Value; // Now parse that value float.TryParse(avgPingString, System.Globalization.NumberStyles.Float, System.Globalization.NumberFormatInfo.InvariantInfo, out avgPingTime); } } if (avgPingTime > 0) { // We parsed the value correctly here }
但是,如果您对统计数据之前的每一行的统计数据感兴趣,则需要一种不同的方法:
64 bytes from 8.8.8.8: icmp_req=2 ttl=46 time=13.9 ms
有 n
行,所有行 在 以 ---
:
List<string> Lines = new List<string>(readData.Replace("\r\n", "\n").Split('\n'));
while (Lines.Count > 0 && !Lines[0].StartsWith("---"))
{
Match M = Regex.Match(Lines[0], @"^[\d]+ bytes from ([^:]+): [^ ]+ ttl=([\d]+) time=([^ ]+) ms");
if (M != null && M.Success)
{
string IP = M.Groups[1].Value;
string TTL = M.Groups[2].Value;
string timeStr = M.Groups[3].Value;
Console.WriteLine(String.Format("Ping to {0} took {2} ms with a ttl of {1}", IP, TTL, timeStr));
// Parsing the timeStr will work the same way as above
}
Lines.RemoveAt(0);
}