我想在本地网络中搜索和查找特定设备并连接到它们。
为了验证我连接的计算机是否正确,我想首先获取网络中所有计算机的 MAC 地址,然后选择每次要进行的连接。
有人可以帮我解决这个问题吗?
到目前为止,我使用 C# 和 TCP 客户端类。
但我不知道如何找到另一台计算机的 MAC 地址,不是应用程序运行的计算机。
我想找到我要连接的计算机的 MAC 地址。
为了解决类似的任务,我创建了一个名为 ArpLookup (nuget) 的小型 MIT 许可库。
特点:
ping
或 arp
进程Async
变体(它在 Windows 上也可以,但在那里不能真正异步)使用后
dotnet add package ArpLookup
像这样
using System.Net.NetworkInformation;
using ArpLookup;
// ...
PhysicalAddress mac = Arp.Lookup(IPAddress.Parse("1.2.3.4"));
PhysicalAddress mac = await Arp.LookupAsync(IPAddress.Parse("1.2.3.4"));
使用所有 Windows 版本原生的
iphlpapi.dll
。这个想法是如果没有返回 mac 则进行 ping 操作,这应该 mac 会更新 ARP 表。
⚠ 仅适用于 LAN
/// <summary>
/// Gets the MAC address associated with the specified IP.<br/>
/// Uses ARP
/// </summary>
/// <param name="ipAddress">The remote IP address.</param>
/// <param name="recheckNo">Number of retries more</param>
/// <remarks>
/// To make sure it's not empty pings before if necessary<br/>
/// ⚠ ONLY WORKS ON LAN
/// </remarks>
/// <returns>The remote machine's MAC address.</returns>
public static PhysicalAddress GetMacAddress(IPAddress ipAddress, int recheckNo = 2)
{
const int MacByteLength = 6;
int length = MacByteLength;
var macBytes = new byte[MacByteLength];
SendARP(BitConverter.ToInt32(ipAddress.GetAddressBytes(), 0), 0, macBytes, ref length);
bool hasAllZeroes = macBytes.All(singleByte => singleByte == 0);
if (hasAllZeroes && recheckNo>0)
{
recheckNo--;
if (CheckPing(ipAddress, 3, 5))
{
Task.Delay(1000).ConfigureAwait(false);
return GetMacAddress(ipAddress, recheckNo);
}
}
if (hasAllZeroes)
return null;
return new PhysicalAddress(macBytes);
}
// http://www.codeproject.com/KB/IP/host_info_within_network.aspx
/// <summary>
/// Windows SendARP using "iphlpapi.dll"
/// </summary>
/// <returns></returns>
[System.Runtime.InteropServices.DllImport("iphlpapi.dll", ExactSpelling = true)]
static extern int SendARP(int DestIP, int SrcIP, byte[] pMacAddr, ref int PhyAddrLen);
/// <summary>
/// Basic Ping request. No Exception return, on error returns false
/// </summary>
/// <param name="ipOrString">IPAddress or string</param>
/// <param name="sec">Timeout in Seconds</param>
/// <param name="ttl">Time to Live</param>
public static bool CheckPing(object ipOrString, int sec = 3, int ttl = 10)
{
var rep = GetPingReply(ipOrString, sec, ttl);
return rep != null ? rep.Status == IPStatus.Success : false;
}
/// <summary>
/// Get Ping Reply
/// </summary>
/// <param name="ipOrString">IPAddress or string</param>
/// <param name="sec">Timeout in Seconds</param>
/// <param name="ttl">Time to Live</param>
/// <returns></returns>
public static PingReply GetPingReply(object ipOrString, int sec = 3, int ttl = 10)
{
int timeout = sec * 1000;
using (Ping pingSender = new Ping())
{
PingOptions options = new PingOptions(ttl, true);
if (ipOrString is string host)
{
return pingSender.Send(host, timeout, new byte[32], options);
}
if (ipOrString is IPAddress ip)
{
return pingSender.Send(ip, timeout, new byte[32], options);
}
throw new ArgumentException("GetPingReply: Argument 'ipOrString' must be a 'IPAddress' or a 'string'");
}
}