[Windows]如何判断指定的IP是否能访问?

一般我们判断是否能够访问指定的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了。

同样的,大家看实现的代码,可以看到代码中已经实际包含了网卡是否断开的检测,可以提取出来,判断网卡是否下线。就不在这里重复了。

分享到: