获取本地计算机的IP地址。

时间:2022-02-25 23:32:45

In C++, what's the easiest way to get the local computer's IP address and subnet mask?

在c++中,获取本地计算机的IP地址和子网掩码最简单的方法是什么?

I want to be able to detect the local machine's IP address in my local network. In my particular case, I have a network with a subnet mask of 255.255.255.0 and my computer's IP address is 192.168.0.5. I need to get these had two values programmatically in order to send a broadcast message to my network (in the form 192.168.0.255, for my particular case)

我希望能够在本地网络中检测本地机器的IP地址。在我的特殊情况下,我有一个网络,子网掩码为255.255.255.0,我的计算机的IP地址是192.168.0.5。我需要以编程方式获得两个值,以便将广播消息发送到我的网络(在表单192.168.0.255中,针对我的特殊情况)

Edit: Many answers were not giving the results I expected because I had two different network IP's. Torial's code did the trick (it gave me both IP addresses). Thanks.

编辑:许多答案并没有给出我所期望的结果,因为我有两个不同的网络IP。他的代码做到了这一点(它给了我两个IP地址)。谢谢。

Edit 2: Thanks to Brian R. Bondy for the info about the subnet mask.

编辑2:感谢Brian R. Bondy关于子网掩码的信息。

12 个解决方案

#1


31  

The question is trickier than it appears, because in many cases there isn't "an IP address for the local computer" so much as a number of different IP addresses. For example, the Mac I'm typing on right now (which is a pretty basic, standard Mac setup) has the following IP addresses associated with it:

这个问题比看起来要棘手,因为在很多情况下,没有“本地计算机的IP地址”,就像许多不同的IP地址一样。例如,我现在正在键入的Mac(这是一个相当基本的标准Mac设置)有以下与之相关的IP地址:

fe80::1%lo0  
127.0.0.1 
::1 
fe80::21f:5bff:fe3f:1b36%en1 
10.0.0.138 
172.16.175.1
192.168.27.1

... and it's not just a matter of figuring out which of the above is "the real IP address", either... they are all "real" and useful; some more useful than others depending on what you are going to use the addresses for.

…这不仅仅是要弄清楚上面哪一个是“真正的IP地址”。它们都是“真实的”和有用的;有些比其他的更有用,这取决于你要使用的地址。

In my experience often the best way to get "an IP address" for your local computer is not to query the local computer at all, but rather to ask the computer your program is talking to what it sees your computer's IP address as. e.g. if you are writing a client program, send a message to the server asking the server to send back as data the IP address that your request came from. That way you will know what the relevant IP address is, given the context of the computer you are communicating with.

在我的经验中,为本地计算机获取“IP地址”的最好方法不是查询本地计算机,而是询问计算机程序正在与计算机的IP地址对话。例如,如果您正在编写一个客户端程序,请向服务器发送一条消息,请求服务器将您的请求所发出的IP地址发回给服务器。这样你就能知道你的IP地址是什么,考虑到你正在与之通信的计算机的上下文。

That said, that trick may not be appropriate for some purposes (e.g. when you're not communicating with a particular computer) so sometimes you just need to gather the list of all the IP addresses associated with your machine. The best way to do that under Unix/Mac (AFAIK) is by calling getifaddrs() and iterating over the results. Under Windows, try GetAdaptersAddresses() to get similar functionality. For example usages of both, see the GetNetworkInterfaceInfos() function in this file.

也就是说,这个技巧可能不适用于某些目的(例如,当您没有与特定的计算机进行通信时),所以有时您只需要收集与您的计算机相关联的所有IP地址的列表。在Unix/Mac (AFAIK)下,最好的方法是调用getifaddrs()并遍历结果。在Windows下,尝试getadaptersad连衣裙()以获得类似的功能。例如,两者的用法,请参阅该文件中的GetNetworkInterfaceInfos()函数。

#2


19  

The problem with all the approaches based on gethostbyname is that you will not get all IP addresses assigned to a particular machine. Servers usually have more than one adapter.

基于gethostbyname的所有方法的问题是,您将无法获得分配给特定机器的所有IP地址。服务器通常有多个适配器。

Here is an example of how you can iterate through all Ipv4 and Ipv6 addresses on the host machine:

下面是一个示例,说明如何遍历主机上的所有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!
}

#3


15  

You can use gethostname followed by gethostbyname to get your local interface internal IP.

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

This returned IP may be different from your external IP though. To get your external IP you would have to communicate with an external server that will tell you what your external IP is. Because the external IP is not yours but it is your routers.

这个返回的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;
}

You can also always just use 127.0.0.1 which represents the local machine always.

您也可以一直使用127.0.0.1表示本地机器。

Subnet mask in Windows:

在Windows子网掩码:

You can get the subnet mask (and gateway and other info) by querying subkeys of this registry entry:

通过查询这个注册表项的子键,可以获得子网掩码(和网关和其他信息):

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

HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Tcpip \参数\ \服务接口

Look for the registry value SubnetMask.

查找注册表值子网掩码。

Other methods to get interface information in Windows:

在Windows中获取界面信息的其他方法:

You could also retrieve the information you're looking for by using: WSAIoctl with this option: SIO_GET_INTERFACE_LIST

您还可以通过使用:SIO_GET_INTERFACE_LIST,检索您正在寻找的信息。

#4


4  

Also, note that "the local IP" might not be a particularly unique thing. If you are on several physical networks (wired+wireless+bluetooth, for example, or a server with lots of Ethernet cards, etc.), or have TAP/TUN interfaces setup, your machine can easily have a whole host of interfaces.

另外,请注意“本地IP”可能不是特别独特的东西。如果你在几个物理网络上(例如有线+无线+蓝牙,或者有很多以太网卡的服务器等等),或者有TAP/TUN接口设置,你的机器就可以很容易地拥有大量的接口。

#5


3  

How to Obtain the IP Address of the Local Machine on the Network seems to describe the solution quite well...

如何在网络上获取本地机器的IP地址似乎很好地描述了解决方案。

#6


3  

You cannot do that in Standard C++.

I'm posting this because it is the only correct answer. Your question asks how to do it in C++. Well, you can't do it in C++. You can do it in Windows, POSIX, Linux, Android, but all those are OS-specific solutions and not part of the language standard.

我发布这个是因为它是唯一正确的答案。你的问题问的是如何在c++中实现它。你不能用c++来做。你可以在Windows, POSIX, Linux, Android上做,但是所有这些都是特定于os的解决方案,而不是语言标准的一部分。

Standard C++ does not have a networking layer at all.

标准c++没有网络层。

I assume you have this wrong assumption that C++ Standard defines the same scope of features as other language standards, Java. While Java might have built-in networking (and even a GUI framework) in the language's own standard library, C++ does not.

我假定您有错误的假设,即c++标准定义了与其他语言标准相同的功能范围,Java。虽然Java在语言本身的标准库中可能有内置的网络(甚至是GUI框架),但是c++没有。

While there are third-party APIs and libraries which can be used by a C++ program, this is in no way the same as saying that you can do it in C++.

虽然有一些第三方的api和库可以被c++程序使用,但这绝不是说你可以用c++来做。

Here is an example to clarify what I mean. You can open a file in C++ because it has an fstream class as part of its standard library. This is not the same thing as using CreateFile(), which is a Windows-specific function and available only for WINAPI.

这里有一个例子来阐明我的意思。您可以在c++中打开一个文件,因为它有一个fstream类作为它的标准库的一部分。这与使用CreateFile()是不一样的,它是一个窗口特定的函数,只适用于WINAPI。

#7


2  

Winsock specific:

Winsock具体:

// Init WinSock
WSADATA wsa_Data;
int wsa_ReturnCode = WSAStartup(0x101,&wsa_Data);

// Get the local hostname
char szHostName[255];
gethostname(szHostName, 255);
struct hostent *host_entry;
host_entry=gethostbyname(szHostName);
char * szLocalIP;
szLocalIP = inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list);
WSACleanup();

#8


2  

from torial: If you use winsock, here's a way: http://tangentsoft.net/wskfaq/examples/ipaddr.html

如果你使用winsock,这里有一个方法:http://tangentsoft.net/wskfaq/examples/ipaddr html。

As for the subnet portion of the question; there is not platform agnostic way to retrieve the subnet mask as the POSIX socket API (which all modern operating systems implement) does not specify this. So you will have to use whatever method is available on the platform you are using.

关于该问题的子网部分;没有平台不可知的方法来检索子网掩码,因为POSIX套接字API(所有现代操作系统实现)都没有指定它。因此,您将不得不使用您正在使用的平台上可用的任何方法。

#9


1  

I was able to do it using DNS service under VS2013 with the following code:

我可以在VS2013下使用DNS服务使用以下代码:

#include <Windns.h>

WSADATA wsa_Data;

int wsa_ReturnCode = WSAStartup(0x101, &wsa_Data);

gethostname(hostName, 256);
PDNS_RECORD pDnsRecord;

DNS_STATUS statsus = DnsQuery(hostName, DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pDnsRecord, NULL);
IN_ADDR ipaddr;
ipaddr.S_un.S_addr = (pDnsRecord->Data.A.IpAddress);
printf("The IP address of the host %s is %s \n", hostName, inet_ntoa(ipaddr));

DnsRecordListFree(&pDnsRecord, DnsFreeRecordList);

I had to add Dnsapi.lib as addictional dependency in linker option.

我必须添加Dnsapi。lib在链接器选项中作为成瘾依赖。

Reference here.

参考这里。

#10


0  

Can't you just send to INADDR_BROADCAST? Admittedly, that'll send on all interfaces - but that's rarely a problem.

你不能直接寄到INADDR_BROADCAST吗?诚然,这将会发送所有的接口——但这很少是一个问题。

Otherwise, ioctl and SIOCGIFBRDADDR should get you the address on *nix, and WSAioctl and SIO_GET_BROADCAST_ADDRESS on win32.

否则,ioctl和SIOCGIFBRDADDR将在win32上为您提供*nix上的地址,以及WSAioctl和SIO_GET_BROADCAST_ADDRESS。

#11


0  

In DEV C++, I used pure C with WIN32, with this given piece of code:

在DEV c++中,我使用了纯C和WIN32,并给出了这段代码:

case IDC_IP:

             gethostname(szHostName, 255);
             host_entry=gethostbyname(szHostName);
             szLocalIP = inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list);
             //WSACleanup(); 
             writeInTextBox("\n");
             writeInTextBox("IP: "); 
             writeInTextBox(szLocalIP);
             break;

When I click the button 'show ip', it works. But on the second time, the program quits (without warning or error). When I do:

当我点击“显示ip”按钮时,它就有效了。但是第二次,程序退出(没有警告或错误)。当我做:

//WSACleanup(); 

The program does not quit, even clicking the same button multiple times with fastest speed. So WSACleanup() may not work well with Dev-C++..

该程序不会退出,甚至会以最快的速度多次点击同一个按钮。因此,WSACleanup()可能不适用于devc ++。

#12


0  

I suggest my code.

我建议我的代码。

DllExport void get_local_ips(boost::container::vector<wstring>& ips)
{
   IP_ADAPTER_ADDRESSES*       adapters  = NULL;
   IP_ADAPTER_ADDRESSES*       adapter       = NULL;
   IP_ADAPTER_UNICAST_ADDRESS* adr           = NULL;
   ULONG                       adapter_size = 0;
   ULONG                       err           = 0;
   SOCKADDR_IN*                sockaddr  = NULL;

   err = ::GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, NULL, NULL, &adapter_size);
   adapters = (IP_ADAPTER_ADDRESSES*)malloc(adapter_size);
   err = ::GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, NULL, adapters, &adapter_size);

   for (adapter = adapters; NULL != adapter; adapter = adapter->Next)
   {
       if (adapter->IfType     == IF_TYPE_SOFTWARE_LOOPBACK) continue; // Skip Loopback
       if (adapter->OperStatus != IfOperStatusUp) continue;            // Live connection only  

       for (adr = adapter->FirstUnicastAddress;adr != NULL; adr = adr->Next)
       {
           sockaddr = (SOCKADDR_IN*)(adr->Address.lpSockaddr);
           char    ipstr [INET6_ADDRSTRLEN] = { 0 };
           wchar_t ipwstr[INET6_ADDRSTRLEN] = { 0 };
           inet_ntop(AF_INET, &(sockaddr->sin_addr), ipstr, INET_ADDRSTRLEN);
           mbstowcs(ipwstr, ipstr, INET6_ADDRSTRLEN);
           wstring wstr(ipwstr);
           if (wstr != "0.0.0.0") ips.push_back(wstr);                      
       }
   }

   free(adapters);
   adapters = NULL; }

#1


31  

The question is trickier than it appears, because in many cases there isn't "an IP address for the local computer" so much as a number of different IP addresses. For example, the Mac I'm typing on right now (which is a pretty basic, standard Mac setup) has the following IP addresses associated with it:

这个问题比看起来要棘手,因为在很多情况下,没有“本地计算机的IP地址”,就像许多不同的IP地址一样。例如,我现在正在键入的Mac(这是一个相当基本的标准Mac设置)有以下与之相关的IP地址:

fe80::1%lo0  
127.0.0.1 
::1 
fe80::21f:5bff:fe3f:1b36%en1 
10.0.0.138 
172.16.175.1
192.168.27.1

... and it's not just a matter of figuring out which of the above is "the real IP address", either... they are all "real" and useful; some more useful than others depending on what you are going to use the addresses for.

…这不仅仅是要弄清楚上面哪一个是“真正的IP地址”。它们都是“真实的”和有用的;有些比其他的更有用,这取决于你要使用的地址。

In my experience often the best way to get "an IP address" for your local computer is not to query the local computer at all, but rather to ask the computer your program is talking to what it sees your computer's IP address as. e.g. if you are writing a client program, send a message to the server asking the server to send back as data the IP address that your request came from. That way you will know what the relevant IP address is, given the context of the computer you are communicating with.

在我的经验中,为本地计算机获取“IP地址”的最好方法不是查询本地计算机,而是询问计算机程序正在与计算机的IP地址对话。例如,如果您正在编写一个客户端程序,请向服务器发送一条消息,请求服务器将您的请求所发出的IP地址发回给服务器。这样你就能知道你的IP地址是什么,考虑到你正在与之通信的计算机的上下文。

That said, that trick may not be appropriate for some purposes (e.g. when you're not communicating with a particular computer) so sometimes you just need to gather the list of all the IP addresses associated with your machine. The best way to do that under Unix/Mac (AFAIK) is by calling getifaddrs() and iterating over the results. Under Windows, try GetAdaptersAddresses() to get similar functionality. For example usages of both, see the GetNetworkInterfaceInfos() function in this file.

也就是说,这个技巧可能不适用于某些目的(例如,当您没有与特定的计算机进行通信时),所以有时您只需要收集与您的计算机相关联的所有IP地址的列表。在Unix/Mac (AFAIK)下,最好的方法是调用getifaddrs()并遍历结果。在Windows下,尝试getadaptersad连衣裙()以获得类似的功能。例如,两者的用法,请参阅该文件中的GetNetworkInterfaceInfos()函数。

#2


19  

The problem with all the approaches based on gethostbyname is that you will not get all IP addresses assigned to a particular machine. Servers usually have more than one adapter.

基于gethostbyname的所有方法的问题是,您将无法获得分配给特定机器的所有IP地址。服务器通常有多个适配器。

Here is an example of how you can iterate through all Ipv4 and Ipv6 addresses on the host machine:

下面是一个示例,说明如何遍历主机上的所有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!
}

#3


15  

You can use gethostname followed by gethostbyname to get your local interface internal IP.

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

This returned IP may be different from your external IP though. To get your external IP you would have to communicate with an external server that will tell you what your external IP is. Because the external IP is not yours but it is your routers.

这个返回的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;
}

You can also always just use 127.0.0.1 which represents the local machine always.

您也可以一直使用127.0.0.1表示本地机器。

Subnet mask in Windows:

在Windows子网掩码:

You can get the subnet mask (and gateway and other info) by querying subkeys of this registry entry:

通过查询这个注册表项的子键,可以获得子网掩码(和网关和其他信息):

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

HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Tcpip \参数\ \服务接口

Look for the registry value SubnetMask.

查找注册表值子网掩码。

Other methods to get interface information in Windows:

在Windows中获取界面信息的其他方法:

You could also retrieve the information you're looking for by using: WSAIoctl with this option: SIO_GET_INTERFACE_LIST

您还可以通过使用:SIO_GET_INTERFACE_LIST,检索您正在寻找的信息。

#4


4  

Also, note that "the local IP" might not be a particularly unique thing. If you are on several physical networks (wired+wireless+bluetooth, for example, or a server with lots of Ethernet cards, etc.), or have TAP/TUN interfaces setup, your machine can easily have a whole host of interfaces.

另外,请注意“本地IP”可能不是特别独特的东西。如果你在几个物理网络上(例如有线+无线+蓝牙,或者有很多以太网卡的服务器等等),或者有TAP/TUN接口设置,你的机器就可以很容易地拥有大量的接口。

#5


3  

How to Obtain the IP Address of the Local Machine on the Network seems to describe the solution quite well...

如何在网络上获取本地机器的IP地址似乎很好地描述了解决方案。

#6


3  

You cannot do that in Standard C++.

I'm posting this because it is the only correct answer. Your question asks how to do it in C++. Well, you can't do it in C++. You can do it in Windows, POSIX, Linux, Android, but all those are OS-specific solutions and not part of the language standard.

我发布这个是因为它是唯一正确的答案。你的问题问的是如何在c++中实现它。你不能用c++来做。你可以在Windows, POSIX, Linux, Android上做,但是所有这些都是特定于os的解决方案,而不是语言标准的一部分。

Standard C++ does not have a networking layer at all.

标准c++没有网络层。

I assume you have this wrong assumption that C++ Standard defines the same scope of features as other language standards, Java. While Java might have built-in networking (and even a GUI framework) in the language's own standard library, C++ does not.

我假定您有错误的假设,即c++标准定义了与其他语言标准相同的功能范围,Java。虽然Java在语言本身的标准库中可能有内置的网络(甚至是GUI框架),但是c++没有。

While there are third-party APIs and libraries which can be used by a C++ program, this is in no way the same as saying that you can do it in C++.

虽然有一些第三方的api和库可以被c++程序使用,但这绝不是说你可以用c++来做。

Here is an example to clarify what I mean. You can open a file in C++ because it has an fstream class as part of its standard library. This is not the same thing as using CreateFile(), which is a Windows-specific function and available only for WINAPI.

这里有一个例子来阐明我的意思。您可以在c++中打开一个文件,因为它有一个fstream类作为它的标准库的一部分。这与使用CreateFile()是不一样的,它是一个窗口特定的函数,只适用于WINAPI。

#7


2  

Winsock specific:

Winsock具体:

// Init WinSock
WSADATA wsa_Data;
int wsa_ReturnCode = WSAStartup(0x101,&wsa_Data);

// Get the local hostname
char szHostName[255];
gethostname(szHostName, 255);
struct hostent *host_entry;
host_entry=gethostbyname(szHostName);
char * szLocalIP;
szLocalIP = inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list);
WSACleanup();

#8


2  

from torial: If you use winsock, here's a way: http://tangentsoft.net/wskfaq/examples/ipaddr.html

如果你使用winsock,这里有一个方法:http://tangentsoft.net/wskfaq/examples/ipaddr html。

As for the subnet portion of the question; there is not platform agnostic way to retrieve the subnet mask as the POSIX socket API (which all modern operating systems implement) does not specify this. So you will have to use whatever method is available on the platform you are using.

关于该问题的子网部分;没有平台不可知的方法来检索子网掩码,因为POSIX套接字API(所有现代操作系统实现)都没有指定它。因此,您将不得不使用您正在使用的平台上可用的任何方法。

#9


1  

I was able to do it using DNS service under VS2013 with the following code:

我可以在VS2013下使用DNS服务使用以下代码:

#include <Windns.h>

WSADATA wsa_Data;

int wsa_ReturnCode = WSAStartup(0x101, &wsa_Data);

gethostname(hostName, 256);
PDNS_RECORD pDnsRecord;

DNS_STATUS statsus = DnsQuery(hostName, DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pDnsRecord, NULL);
IN_ADDR ipaddr;
ipaddr.S_un.S_addr = (pDnsRecord->Data.A.IpAddress);
printf("The IP address of the host %s is %s \n", hostName, inet_ntoa(ipaddr));

DnsRecordListFree(&pDnsRecord, DnsFreeRecordList);

I had to add Dnsapi.lib as addictional dependency in linker option.

我必须添加Dnsapi。lib在链接器选项中作为成瘾依赖。

Reference here.

参考这里。

#10


0  

Can't you just send to INADDR_BROADCAST? Admittedly, that'll send on all interfaces - but that's rarely a problem.

你不能直接寄到INADDR_BROADCAST吗?诚然,这将会发送所有的接口——但这很少是一个问题。

Otherwise, ioctl and SIOCGIFBRDADDR should get you the address on *nix, and WSAioctl and SIO_GET_BROADCAST_ADDRESS on win32.

否则,ioctl和SIOCGIFBRDADDR将在win32上为您提供*nix上的地址,以及WSAioctl和SIO_GET_BROADCAST_ADDRESS。

#11


0  

In DEV C++, I used pure C with WIN32, with this given piece of code:

在DEV c++中,我使用了纯C和WIN32,并给出了这段代码:

case IDC_IP:

             gethostname(szHostName, 255);
             host_entry=gethostbyname(szHostName);
             szLocalIP = inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list);
             //WSACleanup(); 
             writeInTextBox("\n");
             writeInTextBox("IP: "); 
             writeInTextBox(szLocalIP);
             break;

When I click the button 'show ip', it works. But on the second time, the program quits (without warning or error). When I do:

当我点击“显示ip”按钮时,它就有效了。但是第二次,程序退出(没有警告或错误)。当我做:

//WSACleanup(); 

The program does not quit, even clicking the same button multiple times with fastest speed. So WSACleanup() may not work well with Dev-C++..

该程序不会退出,甚至会以最快的速度多次点击同一个按钮。因此,WSACleanup()可能不适用于devc ++。

#12


0  

I suggest my code.

我建议我的代码。

DllExport void get_local_ips(boost::container::vector<wstring>& ips)
{
   IP_ADAPTER_ADDRESSES*       adapters  = NULL;
   IP_ADAPTER_ADDRESSES*       adapter       = NULL;
   IP_ADAPTER_UNICAST_ADDRESS* adr           = NULL;
   ULONG                       adapter_size = 0;
   ULONG                       err           = 0;
   SOCKADDR_IN*                sockaddr  = NULL;

   err = ::GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, NULL, NULL, &adapter_size);
   adapters = (IP_ADAPTER_ADDRESSES*)malloc(adapter_size);
   err = ::GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, NULL, adapters, &adapter_size);

   for (adapter = adapters; NULL != adapter; adapter = adapter->Next)
   {
       if (adapter->IfType     == IF_TYPE_SOFTWARE_LOOPBACK) continue; // Skip Loopback
       if (adapter->OperStatus != IfOperStatusUp) continue;            // Live connection only  

       for (adr = adapter->FirstUnicastAddress;adr != NULL; adr = adr->Next)
       {
           sockaddr = (SOCKADDR_IN*)(adr->Address.lpSockaddr);
           char    ipstr [INET6_ADDRSTRLEN] = { 0 };
           wchar_t ipwstr[INET6_ADDRSTRLEN] = { 0 };
           inet_ntop(AF_INET, &(sockaddr->sin_addr), ipstr, INET_ADDRSTRLEN);
           mbstowcs(ipwstr, ipstr, INET6_ADDRSTRLEN);
           wstring wstr(ipwstr);
           if (wstr != "0.0.0.0") ips.push_back(wstr);                      
       }
   }

   free(adapters);
   adapters = NULL; }