一、思路(主要用于局域网内)
通过Web获取客户端的IP地址较简单,从客户端向web服务器发送的数据报中(Request对象)中即可解析出,但实际应用中,还要考虑代理服务器,路由器的转发等等。
而获取MAC的过程较复杂,因为客户端向服务器发送的请求对象中不包含MAC地址,因此得到两种思路来获取客户端MAC地址:
(1).在客户端来获取客户机的MAC地址,所以当请求到达客户端后,通过客户端脚本来获取客户端MAC地址,然后再传送给服务器端。
(2).先获取客户端IP地址,然后在局域网中发送ARP请求,通过ARP协议和已知的IP地址来解析客户端的MAC地址
下面为获取IP地址、MAC地址的的代码, 以及通过发送ARP请求解析MAC地址的过程:
二、获取IP地址:
public static string GetWebClientIp()
{
string userIP = "未获取用户IP";
try
{
if (System.Web.HttpContext.Current == null
|| System.Web.HttpContext.Current.Request == null
|| System.Web.HttpContext.Current.Request.ServerVariables == null)
return "";
string CustomerIP = "";
//CDN加速后取到的IP
CustomerIP = System.Web.HttpContext.Current.Request.Headers["Cdn-Src-Ip"];
if (!string.IsNullOrEmpty(CustomerIP))
{
return CustomerIP;
}
CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (!String.IsNullOrEmpty(CustomerIP))
return CustomerIP;
if (System.Web.HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null)
{
CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (CustomerIP == null)
CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
}
else
{
CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
}
if (string.Compare(CustomerIP, "unknown", true) == 0)
return System.Web.HttpContext.Current.Request.UserHostAddress;
return CustomerIP;
}
catch { }
return userIP;
}
三、通过ARP协议由IP地址获取MAC地址
1.两种方式获取MAC:
1.1.只能获取本机的MAC
using System.Management;
public string getMac()
{
ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
ManagementObjectCollection moc2 = mc.GetInstances();
foreach (ManagementObject mo in moc2)
{
if ((bool)mo["IPEnabled"] == true)
{
return mo["MacAddress"].ToString();
mo.Dispose();
}
}
return "";
}
1.2.可获取局域网任意客户机的MAC
using System.Runtime.InteropServices;
using System.Text;
[DllImport("Iphlpapi.dll")]
static extern int SendARP(Int32 DestIP, Int32 SrcIP, ref Int64 MacAddr, ref Int32 PhyAddrLen);
[DllImport("Ws2_32.dll")]
static extern Int32 inet_addr(string ipaddr);
///<summary>
/// SendArp获取MAC地址
///</summary>
///<param name="RemoteIP">目标机器的IP地址如(192.168.1.1)</param>
///<returns>目标机器的mac 地址</returns>
public static string GetMacAddress(string RemoteIP)
{
StringBuilder macAddress = new StringBuilder();
try
{
Int32 remote = inet_addr(RemoteIP);
Int64 macInfo = new Int64();
Int32 length = 6;
SendARP(remote, 0, ref macInfo, ref length);
string temp = Convert.ToString(macInfo, 16).PadLeft(12, '0').ToUpper();
int x = 12;
for (int i = 0; i < 6; i++)
{
if (i == 5)
{
macAddress.Append(temp.Substring(x - 2, 2));
}
else
{
macAddress.Append(temp.Substring(x - 2, 2) + "-");
}
x -= 2;
}
return macAddress.ToString();
}
catch
{
return macAddress.ToString();
}
}
2.原理
首先要知道交换机是通过MAC地址通信的,但是我们是如何获得目标主机的MAC地址呢?这时我们就需要使用ARP协议了,在每台主机中都有一张ARP表,它记录着主机的IP地址和MAC地址的对应关系。
ARP协议是工作在网络层的协议,它负责将IP地址解析为MAC地址。下面讲解ARP的工作原理:
1)如果主机A想发送数据给主机B,主机A首先会检查自己的ARP缓存表,查看是否有主机B的IP地址和MAC地址的对应关系,如果有,则会将主机B的MAC地址作为源MAC地址封装到数据帧中。如果没有,主机A则会发送一个ARP请求信息,请求的目标IP地址是主机B的IP地址,目标MAC地址是MAC地址的广播帧(即FF-FF-FF-FF-FF-FF),源IP地址和MAC地址是主机A的IP地址和MAC地址。
2)当交换机接受到此数据帧之后,发现此数据帧是广播帧,因此,会将此数据帧从非接收的所有接口发送出去。
3)当主机B接受到此数据帧后,会校对IP地址是否是自己的,并将主机A的IP地址和MAC地址的对应关系记录到自己的ARP缓存表中,同时会发送一个ARP应答,其中包括自己的MAC地址。
4)主机A在收到这个回应的数据帧之后,在自己的ARP缓存表中记录主机B的IP地址和MAC地址的对应关系。而此时交换机已经学习到了主机A和主机B的MAC地址了。
四、总结
以前没有接触过网络编程,现在开始接触,做起来感觉要求比cs结构的要求要高一些,需要了解局域网的架构,交换机、路由器的转发原理,也借此机会了解了MAC地址表、ARP缓存表以及路由表等等内容。学无止境,越来越觉得知识太匮乏了,有太多东西需要学习。