为了账号安全,请及时绑定邮箱和手机立即绑定

获取本地计算机的IP地址

获取本地计算机的IP地址

C++
开满天机 2019-10-09 16:30:43
在C ++中,获取本地计算机的IP地址和子网掩码的最简单方法是什么?我希望能够在本地网络中检测本地计算机的IP地址。在我的特定情况下,我的子网掩码为255.255.255.0,计算机的IP地址为192.168.0.5。我需要以编程方式使它们具有两个值,以便将广播消息发送到我的网络(对于我的特殊情况,格式为192.168.0.255)编辑:许多答案没有给出我期望的结果,因为我有两个不同的网络IP。Torial的代码成功了(它给了我两个IP地址)。谢谢。
查看完整描述

3 回答

?
一只斗牛犬

TA贡献1784条经验 获得超2个赞

所有基于gethostbyname的方法的问题在于,您不会获得分配给特定计算机的所有IP地址。服务器通常具有多个适配器。


这是一个如何遍历主机上所有Ipv4和Ipv6地址的示例:


void ListIpAddresses(IpAddresses& ipAddrs)

{

  IP_ADAPTER_ADDRESSES* adapter_addresses(NULL);

  IP_ADAPTER_ADDRESSES* adapter(NULL);


  // Start with a 16 KB buffer and resize if needed -

  // multiple attempts in case interfaces change while

  // we are in the middle of querying them.

  DWORD adapter_addresses_buffer_size = 16 * KB;

  for (int attempts = 0; attempts != 3; ++attempts)

  {

    adapter_addresses = (IP_ADAPTER_ADDRESSES*)malloc(adapter_addresses_buffer_size);

    assert(adapter_addresses);


    DWORD error = ::GetAdaptersAddresses(

      AF_UNSPEC, 

      GAA_FLAG_SKIP_ANYCAST | 

        GAA_FLAG_SKIP_MULTICAST | 

        GAA_FLAG_SKIP_DNS_SERVER |

        GAA_FLAG_SKIP_FRIENDLY_NAME, 

      NULL, 

      adapter_addresses,

      &adapter_addresses_buffer_size);


    if (ERROR_SUCCESS == error)

    {

      // We're done here, people!

      break;

    }

    else if (ERROR_BUFFER_OVERFLOW == error)

    {

      // Try again with the new size

      free(adapter_addresses);

      adapter_addresses = NULL;


      continue;

    }

    else

    {

      // Unexpected error code - log and throw

      free(adapter_addresses);

      adapter_addresses = NULL;


      // @todo

      LOG_AND_THROW_HERE();

    }

  }


  // Iterate through all of the adapters

  for (adapter = adapter_addresses; NULL != adapter; adapter = adapter->Next)

  {

    // Skip loopback adapters

    if (IF_TYPE_SOFTWARE_LOOPBACK == adapter->IfType)

    {

      continue;

    }


    // Parse all IPv4 and IPv6 addresses

    for (

      IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress; 

      NULL != address;

      address = address->Next)

    {

      auto family = address->Address.lpSockaddr->sa_family;

      if (AF_INET == family)

      {

        // IPv4

        SOCKADDR_IN* ipv4 = reinterpret_cast<SOCKADDR_IN*>(address->Address.lpSockaddr);


        char str_buffer[INET_ADDRSTRLEN] = {0};

        inet_ntop(AF_INET, &(ipv4->sin_addr), str_buffer, INET_ADDRSTRLEN);

        ipAddrs.mIpv4.push_back(str_buffer);

      }

      else if (AF_INET6 == family)

      {

        // IPv6

        SOCKADDR_IN6* ipv6 = reinterpret_cast<SOCKADDR_IN6*>(address->Address.lpSockaddr);


        char str_buffer[INET6_ADDRSTRLEN] = {0};

        inet_ntop(AF_INET6, &(ipv6->sin6_addr), str_buffer, INET6_ADDRSTRLEN);


        std::string ipv6_str(str_buffer);


        // Detect and skip non-external addresses

        bool is_link_local(false);

        bool is_special_use(false);


        if (0 == ipv6_str.find("fe"))

        {

          char c = ipv6_str[2];

          if (c == '8' || c == '9' || c == 'a' || c == 'b')

          {

            is_link_local = true;

          }

        }

        else if (0 == ipv6_str.find("2001:0:"))

        {

          is_special_use = true;

        }


        if (! (is_link_local || is_special_use))

        {

          ipAddrs.mIpv6.push_back(ipv6_str);

        }

      }

      else

      {

        // Skip all other types of addresses

        continue;

      }

    }

  }


  // Cleanup

  free(adapter_addresses);

  adapter_addresses = NULL;


  // Cheers!

}


查看完整回答
反对 回复 2019-10-09
?
喵喔喔

TA贡献1735条经验 获得超5个赞

您可以使用gethostname后跟gethostbyname来获取本地接口内部IP。


该返回的IP可能与您的外部IP不同。要获取外部IP,您必须与外部服务器通信,该服务器将告诉您外部IP是什么。因为外部IP不是您的,而是您的路由器。


//Example: b1 == 192, b2 == 168, b3 == 0, b4 == 100

struct IPv4

{

    unsigned char b1, b2, b3, b4;

};


bool getMyIP(IPv4 & myIP)

{

    char szBuffer[1024];


    #ifdef WIN32

    WSADATA wsaData;

    WORD wVersionRequested = MAKEWORD(2, 0);

    if(::WSAStartup(wVersionRequested, &wsaData) != 0)

        return false;

    #endif



    if(gethostname(szBuffer, sizeof(szBuffer)) == SOCKET_ERROR)

    {

      #ifdef WIN32

      WSACleanup();

      #endif

      return false;

    }


    struct hostent *host = gethostbyname(szBuffer);

    if(host == NULL)

    {

      #ifdef WIN32

      WSACleanup();

      #endif

      return false;

    }


    //Obtain the computer's IP

    myIP.b1 = ((struct in_addr *)(host->h_addr))->S_un.S_un_b.s_b1;

    myIP.b2 = ((struct in_addr *)(host->h_addr))->S_un.S_un_b.s_b2;

    myIP.b3 = ((struct in_addr *)(host->h_addr))->S_un.S_un_b.s_b3;

    myIP.b4 = ((struct in_addr *)(host->h_addr))->S_un.S_un_b.s_b4;


    #ifdef WIN32

    WSACleanup();

    #endif

    return true;

}

您也可以始终只使用127.0.0.1,它始终代表本地计算机。


Windows中的子网掩码:


您可以通过查询以下注册表项的子项来获取子网掩码(以及网关和其他信息):


HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ Tcpip \ Parameters \ Interfaces


查找注册表值SubnetMask。


在Windows中获取接口信息的其他方法:


您还可以通过以下方式检索所需的信息: WSAIoctl,带有以下选项:SIO_GET_INTERFACE_LIST


查看完整回答
反对 回复 2019-10-09
  • 3 回答
  • 0 关注
  • 493 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信