一般我们判断是否能够访问指定的IP地址时,一般都是采用PING或者尝试连接到指定的TCP端口的方式,在上面的基础上,实际上通过尽快的排除明显不可能访问的目标,来加快测试的速度。
下面的C++代码提供给大家,方便的判断是否能够路由到指定的目标:
/*判断是否能够路由到指定的IP Parameters ARemote : 用来确定网卡的远程地址 Returns 在以下情况下,返回false: 1.无法路由到远程地址; 2.网卡被禁用或网卡断开连接 否则,返回true */ bool __fastcall CanRouteTo(const in_addr &ARemote) { MIB_IFTABLE *ATable; DWORD ASize=0; int ARetVal=0;//Unknown if(GetIfTable(NULL,&ASize,false)==ERROR_INSUFFICIENT_BUFFER) { ATable=(MIB_IFTABLE *)malloc(ASize); PMIB_IPFORWARDTABLE pIpForwardTable=NULL; try { if(GetIfTable(ATable,&ASize,false)==ERROR_SUCCESS) { ASize=0; int ALastMatric; if(GetIpForwardTable(pIpForwardTable, &ASize, false)==ERROR_INSUFFICIENT_BUFFER) { pIpForwardTable = (PMIB_IPFORWARDTABLE)malloc(ASize); if(GetIpForwardTable(pIpForwardTable, &ASize, false)==ERROR_SUCCESS) { for(int j=0; (j<pIpForwardTable->dwNumEntries)&&(ARetVal==0); j++) { if((pIpForwardTable->table[j].dwForwardMask&ARemote.S_un.S_addr)==pIpForwardTable->table[j].dwForwardDest) { if(pIpForwardTable->table[j].dwForwardType>=3) { for(DWORD i=0; i<ATable->dwNumEntries; i++) { if(pIpForwardTable->table[j].dwForwardIfIndex==ATable->table[i].dwIndex) { switch(ATable->table[i].dwOperStatus) { case MIB_IF_OPER_STATUS_OPERATIONAL: case MIB_IF_OPER_STATUS_CONNECTED: ARetVal=1;//Connected break; default: ARetVal=2;//Disconnected break; } break; } } } } } } } } } __finally { free(ATable); if(pIpForwardTable) free(pIpForwardTable); } } return (ARetVal==1); }
这个函数的缺陷是每次是每次都会枚举路由表和网卡状态,实际上进一步优化的话,我们可以通过缓存路由表来提高效率。这时你可能有新的疑问?路由表变了怎么办?IP地址变了怎么办?网卡断开或者被禁用了我怎么检测到呢?
好吧,我们承认这些都是合理担忧,所以我这里告诉大家两个API,NotifyRouteChange和NotifyAddrChange可以分别用于检测路由表和地址的变更。您可能认为没有网卡检测功能,实际上,网卡被禁用或才启用时,路由表会发生变更,所以可以满足上面的要求了。只需要在检测到路由表和IP变更时,更新下路由表就OK了。
同样的,大家看实现的代码,可以看到代码中已经实际包含了网卡是否断开的检测,可以提取出来,判断网卡是否下线。就不在这里重复了。