在我的Xamarin Forms应用程序中,我试图发现我连接到的本地网络上的所有设备。我的方法是首先获取设备IP地址,并使用前3个数字来了解网关是什么(第一个数字始终为192)。然后,ping该网关上的每个地址。这是我的代码:
public partial class MainPage : ContentPage
{
private List<Device> discoveredDevices = new List<Device>();
public MainPage()
{
InitializeComponent();
Ping_all();
}
private string GetCurrentIp()
{
IPAddress[] addresses = Dns.GetHostAddresses(Dns.GetHostName());
string ipAddress = string.Empty;
if (addresses != null && addresses[0] != null)
{
ipAddress = addresses[0].ToString();
}
else
{
ipAddress = null;
}
return ipAddress;
}
public void Ping_all()
{
string ip = GetCurrentIp();
if (ip != null)
{
//Extracting and pinging all other ip's.
string[] array = ip.Split('.');
string gateway = array[0] + "." + array[1] + "." + array[2];
for (int i = 2; i <= 255; i++)
{
string ping_var = $"{gateway}.{i}";
//time in milliseconds
Ping(ping_var, 4, 4000);
}
}
}
public void Ping(string host, int attempts, int timeout)
{
for (int i = 0; i < attempts; i++)
{
new Thread(delegate ()
{
try
{
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
ping.PingCompleted += new PingCompletedEventHandler(PingCompleted);
ping.SendAsync(host, timeout, host);
// PingCompleted never gets called
}
catch(Exception e)
{
// Do nothing and let it try again until the attempts are exausted.
// Exceptions are thrown for normal ping failurs like address lookup
// failed. For this reason we are supressing errors.
}
}).Start();
}
}
private void PingCompleted(object sender, PingCompletedEventArgs e)
{
string ip = (string)e.UserState;
if (e.Reply != null && e.Reply.Status == IPStatus.Success)
{
string hostname = GetHostName(ip);
string macaddres = GetMacAddress(ip);
var device = new Device()
{
Hostname = hostname,
IpAddress = ip,
MacAddress = macaddres
};
discoveredDevices.Add(device);
}
}
public string GetHostName(string ipAddress)
{
try
{
IPHostEntry entry = Dns.GetHostEntry(ipAddress);
if (entry != null)
{
return entry.HostName;
}
}
catch (SocketException)
{
}
return null;
}
public string GetMacAddress(string ipAddress)
{
string macAddress = string.Empty;
System.Diagnostics.Process Process = new System.Diagnostics.Process();
Process.StartInfo.FileName = "arp";
Process.StartInfo.Arguments = "-a " + ipAddress;
Process.StartInfo.UseShellExecute = false;
Process.StartInfo.RedirectStandardOutput = true;
Process.StartInfo.CreateNoWindow = true;
Process.Start();
string strOutput = Process.StandardOutput.ReadToEnd();
string[] substrings = strOutput.Split('-');
if (substrings.Length >= 8)
{
macAddress = substrings[3].Substring(Math.Max(0, substrings[3].Length - 2))
+ "-" + substrings[4] + "-" + substrings[5] + "-" + substrings[6]
+ "-" + substrings[7] + "-"
+ substrings[8].Substring(0, 2);
return macAddress;
}
else
{
return "OWN Machine";
}
}
}
我进入尝试ping的部分:
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
ping.PingCompleted += new PingCompletedEventHandler(PingCompleted);
ping.SendAsync(host, timeout, host);
但是PingCompleted
从未被调用。也不抛出异常。知道为什么吗?我正在物理Android设备上运行它。
编辑
PingCompleted
现在开始受到我的呼唤,不确定为什么以前不起作用。但由于它找不到资源,它现在在GetMacAddress
行的Process.Start();
函数中崩溃。
答案 0 :(得分:0)
我最终使用了这个非常强大且易于使用的库:
https://github.com/Yortw/RSSDP
它实际上并没有找到网络上的所有设备,而是使用SSDP(简单搜索发现协议)来快速查找正在网络上使用此协议广播服务的所有设备。我将其过滤为仅扫描运行我的应用程序的设备,而这正是我真正需要的。只需一秒钟即可发现我的设备,这比对255个地址执行ping操作要快得多。
在文档中,您将看到:
var deviceDefinition = new SsdpRootDevice()
{
CacheLifetime = TimeSpan.FromMinutes(30), //How long SSDP clients can cache this info.
Location = new Uri("http://mydevice/descriptiondocument.xml"), // Must point to the URL that serves your devices UPnP description document.
DeviceTypeNamespace = "my-namespace",
DeviceType = "MyCustomDevice",
FriendlyName = "Custom Device 1",
Manufacturer = "Me",
ModelName = "MyCustomDevice",
Uuid = GetPersistentUuid() // This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.
};
对于Location
,我将其设置为设备的IP。这样发现它的另一台设备也可以拥有IP。我不认为应该以这种方式使用它,但是它对我有用,我不知道为什么不这样做。
我在2个物理Android设备上进行了测试。