找回密码
 加入
搜索
查看: 4783|回复: 4

[网络通信] 【已解决】如何将 C# 通过Iphlpapi.dll API操作路由表 改成AU3呢

[复制链接]
发表于 2013-5-18 19:07:08 | 显示全部楼层 |阅读模式
本帖最后由 风雨网络 于 2013-5-18 20:38 编辑

这个是网上找的代码 怎么改成AU3 的呀!

最简单的方式是在C#里调用cmd的route命令,优点是简单,开发速度快。缺点显而易见,运行效率非常低,添加一条记录可能需要200ms以上。如果添加记录极多的话,这个效率就让人难以接受了。
这里我就讲一下第二种用法,通过调用win api来修改路由表,达到高效率添加的目的。这个问题看似很简单。实际操作起来却遇到很多麻烦。一些细节的描述在网上很少有人提及。
核心函数是:
[DllImport("Iphlpapi.dll")]
       [return: MarshalAs(UnmanagedType.U4)]
       public static extern int CreateIpForwardEntry(ref MIB_IPFORWARDROW pRoute);
CreateIpForwardEntry  这个函数,入口参数是一个结构,如下所示
[StructLayout(LayoutKind.Sequential)]
       public struct MIB_IPFORWARDROW
       {
           public UInt32 dwForwardDest;        //destination IP address.
           public UInt32 dwForwardMask;        //Subnet mask
           public UInt32 dwForwardPolicy;      //conditions for multi-path route. Unused, specify 0.
           public UInt32 dwForwardNextHop;     //IP address of the next hop. Own address?
           public UInt32 dwForwardIfIndex;     //index of interface
           public UInt32 dwForwardType;        //route type
           public UInt32 dwForwardProto;       //routing protocol.
           public UInt32 dwForwardAge;         //age of route.
           public UInt32 dwForwardNextHopAS;   //autonomous system number. 0 if not relevant
           public int dwForwardMetric1;     //-1 if not used (goes for all metrics)
           public int dwForwardMetric2;
           public int dwForwardMetric3;
           public int dwForwardMetric4;
           public int dwForwardMetric5;
       }
我们把上面这个api函数稍微改造一下,适合C#调用

public static int createIpForwardEntry(UInt32 destIPAddress, UInt32 destMask, UInt32 nextHopIPAddress, UInt32 ifIndex, int metric)
       {
           MIB_IPFORWARDROW mifr = new MIB_IPFORWARDROW();
           mifr.dwForwardDest = destIPAddress;
           mifr.dwForwardMask = destMask;
           mifr.dwForwardNextHop = nextHopIPAddress;
           mifr.dwForwardIfIndex = ifIndex;
           mifr.dwForwardPolicy = Convert.ToUInt32(0);
           mifr.dwForwardType = Convert.ToUInt32(4);
           mifr.dwForwardProto = Convert.ToUInt32(3);
           mifr.dwForwardAge = Convert.ToUInt32(0);
           mifr.dwForwardNextHopAS = Convert.ToUInt32(0);
           mifr.dwForwardMetric1 = metric;
           mifr.dwForwardMetric2 = -1;
           mifr.dwForwardMetric3 = -1;
           mifr.dwForwardMetric4 = -1;
           mifr.dwForwardMetric5 = -1;
           return CreateIpForwardEntry(ref mifr);
       }
其中 mifr.dwForwardDest 是ip地址,
mifr.dwForwardMask 是子网掩码。
mifr.dwForwardNextHop 是网关地址
以上三个参数比较好理解和使用,有一个注意点就是这三个参数都是32位无符号整形,我们平时使用的ip地址都是字符串形式的,比如"192.168.0.1",这就涉及到一个ip地址由string转换成uint32过程
ip地址4个字节,无符号32位整形正好能够保存ip的所有数据
//IP转换成数字地址
       public static uint IPToInt(string ipAddress)
       {
           string disjunctiveStr = ".,:";
           char[] delimiter = disjunctiveStr.ToCharArray();
           string[] startIP = null;
           for (int i = 1; i <= 5; i++)
           {
               startIP = ipAddress.Split(delimiter, i);
           }
           string a1 = startIP[0].ToString();
           string a2 = startIP[1].ToString();
           string a3 = startIP[2].ToString();
           string a4 = startIP[3].ToString();
           uint U1 = uint.Parse(a1);
           uint U2 = uint.Parse(a2);
           uint U3 = uint.Parse(a3);
           uint U4 = uint.Parse(a4);

           uint U = U4 << 24;
           U += U3 << 16;
           U += U2 << 8;
           U += U1;
           return U;
       }
转换函数如上,需要注意的是msdn上明确指出,转换的ip地址,需要是低字节在前,就是说192.168.0.1这个ip地址,最后的0x01要放在uint的32位的前面8个字节上。
问题最大的就是 dwForwardIfIndex 和 dwForwardMetric1 这两个参数如何获得
方法如下:
          uint forwardMetric = 0;
           int pdwSize = 20000;
           pIPForwardTable = new byte[pdwSize];
           iphlpapi.GetIpForwardTable(pIPForwardTable, out pdwSize, true);
           ForwardIfIndex = pIPForwardTable[20];
以上代码获得ForwardIfIndex 的值,这个值被存放在 pIPForwardTable 下标为20的地方 囧
可以参考 参考链接  这个非常隐蔽。

      [DllImport("Iphlpapi.dll")]
       public static extern uint GetIpInterfaceEntry(ref MIB_IPINTERFACE_ROW pRoute);
       [DllImport("iphlpapi.dll", CharSet = CharSet.Auto)]
       public static extern int GetBestInterface(UInt32 DestAddr, out UInt32 BestIfIndex);

               iphlpapi.GetBestInterface(GetNetworkInfo.IPToInt(strIP), out interfaceIndex);
               iphlpapi.MIB_IPINTERFACE_ROW aRow = new iphlpapi.MIB_IPINTERFACE_ROW();
               aRow.Family = 2;
               aRow.InterfaceLuid = 0;
               aRow.InterfaceIndex = interfaceIndex;
               //GetIpInterfaceEntry is available in Vista/2008 server or higher
               uint errorCode = iphlpapi.GetIpInterfaceEntry(ref aRow);
               if (errorCode != 0)
               {
                   AppendRichTextBox("Can't get Metric number");
                   sr.Close();
                   return;
               }
               forwardMetric = aRow.Metric;
以上代码可以获得  forwardMetric 的值,这样,所有参数就都全了,最终调用:

if (iphlpapi.createIpForwardEntry(GetNetworkInfo.IPToInt(strIP),
                   GetNetworkInfo.IPToInt(SubnetMask),
                   GetNetworkInfo.IPToInt(defaultGateway), ForwardIfIndex, (int)forwardMetric + 5) != 0)
               {
                   //添加错误
               }
forwardMetric 最终要加上一个offset,不能比 aRow.Metric 小
要删除记录,那就比较简单了,把结构当中的 mifr.dwForwardMetric1 = -1 即可
public static int deleteIpForwardEntry(UInt32 destIPAddress, UInt32 destMask, UInt32 nextHopIPAddress, UInt32 ifIndex)
       {
           MIB_IPFORWARDROW mifr = new MIB_IPFORWARDROW();
           mifr.dwForwardDest = destIPAddress;
           mifr.dwForwardMask = destMask;
           mifr.dwForwardNextHop = nextHopIPAddress;
           mifr.dwForwardIfIndex = ifIndex;
           mifr.dwForwardPolicy = Convert.ToUInt32(0);
           mifr.dwForwardType = Convert.ToUInt32(4);
           mifr.dwForwardProto = Convert.ToUInt32(3);
           mifr.dwForwardAge = Convert.ToUInt32(0);
           mifr.dwForwardNextHopAS = Convert.ToUInt32(0);
            mifr.dwForwardMetric1 = -1;
           mifr.dwForwardMetric2 = -1;
           mifr.dwForwardMetric3 = -1;
           mifr.dwForwardMetric4 = -1;
           mifr.dwForwardMetric5 = -1;
           return DeleteIpForwardEntry(ref mifr);
       }
以上的做法虽然有点复杂,但是好处是显而易见的,运行效率非常高,运行createIpForwardEntry方法几百次仅仅需要不到1s的时间。
发表于 2013-5-18 19:24:17 | 显示全部楼层
 楼主| 发表于 2013-5-18 20:37:51 | 显示全部楼层
感谢 pusofalse   问题解决了!
发表于 2013-5-18 22:13:43 | 显示全部楼层
过来学习一下!
发表于 2013-8-28 18:58:04 | 显示全部楼层
赶紧看看怎么回事..找了一下午了
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-12-26 02:14 , Processed in 0.073783 second(s), 23 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表