获取本地计算机的IP地址
在C ++中,获取本地计算机的IP地址和子网掩码的最简单方法是什么?
我希望能够在本地networking中检测本地计算机的IP地址。 在我的情况下,我有一个networking,其子网掩码为255.255.255.0,我的电脑的IP地址是192.168.0.5。 我需要得到这些有两个值编程为了发送一个广播消息到我的networking(forms192.168.0.255,对于我的具体情况)
编辑:许多答案没有给我预期的结果,因为我有两个不同的networkingIP。 Torial的代码做了窍门(它给了我两个IP地址)。 谢谢。
编辑2:感谢Brian R. Bondy关于子网掩码的信息。
这个问题比看起来更复杂,因为在许多情况下,没有“本地计算机的IP地址”,而是多个不同的IP地址。 例如,我现在正在input的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
…这不仅仅是要弄清楚上面的哪一个是“真正的IP地址”,它们都是“真实的”和有用的; 一些比别人更有用取决于你将要使用的地址。
根据我的经验,为本地计算机获取“IP地址”的最佳方法不是查询本地计算机,而是要求计算机上的程序正在与您的计算机的IP地址相对应。 例如,如果您正在编写客户端程序,则向服务器发送一条消息,要求服务器将您请求的IP地址作为数据发回。 这样你就可以知道相关的 IP地址是什么,给你正在通信的计算机的上下文。
也就是说,这个技巧可能不适合某些目的(例如,当您不与特定的计算机通信时),所以有时您只需要收集与您的计算机相关的所有IP地址的列表。 在Unix / Mac(AFAIK)下做这件事的最好方法是调用getifaddrs()并遍历结果。 在Windows下,尝试GetAdaptersAddresses()以获得类似的function。 例如两者的用法,请参阅此文件中的GetNetworkInterfaceInfos()函数。
基于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! }
您可以使用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中的子网掩码:
您可以通过查询此registry项的子项来获取子网掩码(以及网关和其他信息):
HKEY_LOCAL_MACHINE \系统\ CurrentControlSet \服务\ TCPIP \参数\接口
查找registry值SubnetMask。
在Windows中获取接口信息的其他方法:
您也可以通过使用以下选项来检索您正在查找的信息: WSAIoctl :SIO_GET_INTERFACE_LIST
此外,请注意,“本地IP”可能不是一个特别的事情。 如果您使用的是多个物理networking(例如有线+无线+蓝牙或者具有大量以太网卡的服务器等),或者设置了TAP / TUN接口,则您的机器可以轻松拥有大量接口。
如何获得本地networking的IP地址在networking上似乎很好地描述了解决scheme…
从torial:如果您使用winsock,这是一个方法: http : //tangentsoft.net/wskfaq/examples/ipaddr.html
至于问题的子网部分; 没有平台不可知的方式来检索子网掩码作为POSIX套接字API(所有现代操作系统实现)没有指定这个。 所以你将不得不使用你正在使用的平台上的任何方法。
你不能在标准C ++中做到这一点。
我张贴这是因为这是唯一正确的答案。 你的问题问如何在C ++中做到这一点。 那么,你不能在C ++中做到这一点。 您可以在Windows,POSIX,Linux,Android中执行,但所有这些都是操作系统特定的解决scheme,而不是语言标准的一部分。
标准C ++ 根本没有networking层 。
我假设你有这个错误的假设,C ++标准定义了与其他语言标准Java相同的function范围。 虽然Java可能在语言自己的标准库中内置了networking(甚至是GUI框架),但是C ++却没有。
虽然有第三方的API和库可以被C ++程序使用,但这绝不是说你可以用C ++来做到这一点。
这里是一个例子来澄清我的意思。 你可以用C ++打开一个文件,因为它有一个fstream
类作为其标准库的一部分。 这与使用CreateFile()
,它是一个Windows特有的函数,仅适用于WINAPI。
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();
你不能只发送到INADDR_BROADCAST ? 无可否认,这将在所有接口上发送 – 但这不是一个问题。
否则,ioctl和SIOCGIFBRDADDR应该在* nix上获得地址,在win32上获得WSAioctl和SIO_GET_BROADCAST_ADDRESS 。
我能够使用下面的代码使用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);
我必须添加Dnsapi.lib作为链接器选项中的依赖依赖。
在这里引用。
在DEV C ++中,我使用了WIN32下的纯C语言,使用了这段代码:
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;
当我点击button“显示IP”,它的作品。 但第二次,程序退出(没有警告或错误)。 当我做:
//WSACleanup();
程序不会退出,甚至以最快的速度多次点击相同的button。 所以WSACleanup()可能不适用于Dev-C ++。
最简单的方法!
系统( “IPCONFIG”);
最后不用担心:)