Obtenir l’adresse IP de l’ordinateur local

En C ++, quel est le moyen le plus simple d’obtenir l’adresse IP et le masque de sous-réseau de l’ordinateur local?

Je veux pouvoir détecter l’adresse IP de la machine locale sur mon réseau local. Dans mon cas particulier, j’ai un réseau avec un masque de sous-réseau de 255.255.255.0 et l’adresse IP de mon ordinateur est 192.168.0.5. Je dois obtenir ces deux valeurs par programmation afin d’envoyer un message de diffusion à mon réseau (sous la forme 192.168.0.255, pour mon cas particulier)

Edit: Beaucoup de réponses ne donnaient pas les résultats escomptés car j’avais deux IP de réseau différentes. Le code de Torial a fait l’affaire (il m’a donné les deux adresses IP). Merci.

Edit 2: Merci à Brian R. Bondy pour les informations sur le masque de sous-réseau.

La question est plus délicate qu’elle n’apparaît, car dans de nombreux cas, il n’ya pas «d’adresse IP pour l’ordinateur local», mais bien un nombre d’adresses IP différentes. Par exemple, le Mac sur lequel je tape actuellement (une configuration Mac standard de base) est associé aux adresses IP suivantes:

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 

… et ce n’est pas juste une question de savoir lequel de ces éléments est “la véritable adresse IP”, soit … ils sont tous “réels” et utiles; certains sont plus utiles que d’autres en fonction de l’utilisation des adresses.

D’après mon expérience, le meilleur moyen d’obtenir une “adresse IP” pour votre ordinateur local n’est pas de demander à l’ordinateur local, mais de demander à l’ordinateur auquel votre programme s’adresse ce qu’il considère comme l’adresse IP de votre ordinateur. Par exemple, si vous écrivez un programme client, envoyez un message au serveur pour lui demander de renvoyer en tant que données l’adresse IP d’où provient votre demande. De cette façon, vous saurez quelle est l’adresse IP pertinente , compte tenu du contexte de l’ordinateur avec lequel vous communiquez.

Cela dit, cette astuce peut ne pas convenir à certaines fins (par exemple, lorsque vous ne communiquez pas avec un ordinateur particulier). Il vous suffit donc parfois de rassembler la liste de toutes les adresses IP associées à votre ordinateur. La meilleure façon de faire cela sous Unix / Mac (AFAIK) consiste à appeler getifaddrs () et à itérer les résultats. Sous Windows, essayez GetAdaptersAddresses () pour obtenir des fonctionnalités similaires. Pour des exemples d’utilisation des deux, consultez la fonction GetNetworkInterfaceInfos () dans ce fichier .

Le problème avec toutes les approches basées sur gethostbyname est que vous n’obtiendrez pas toutes les adresses IP assignées à une machine particulière. Les serveurs ont généralement plusieurs adaptateurs.

Voici un exemple de la manière dont vous pouvez parcourir toutes les adresses Ipv4 et Ipv6 sur la machine hôte:

 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(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(address->Address.lpSockaddr); char str_buffer[INET6_ADDRSTRLEN] = {0}; inet_ntop(AF_INET6, &(ipv6->sin6_addr), str_buffer, INET6_ADDRSTRLEN); std::ssortingng 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! } 

Vous pouvez utiliser gethostname suivi de gethostbyname pour obtenir l’adresse IP interne de votre interface locale.

Cette adresse IP renvoyée peut être différente de votre adresse IP externe. Pour obtenir votre adresse IP externe, vous devez communiquer avec un serveur externe qui vous indiquera votre adresse IP externe. Parce que l’IP externe n’est pas à vous mais c’est vos routeurs.

 //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; } 

Vous pouvez aussi toujours utiliser 127.0.0.1, qui représente toujours la machine locale.

Masque de sous-réseau dans Windows:

Vous pouvez obtenir le masque de sous-réseau (et la passerelle et d’autres informations) en interrogeant les sous-clés de cette entrée de registre:

HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ Tcpip \ Paramètres \ Interfaces

Recherchez la valeur de registre SubnetMask.

Autres méthodes pour obtenir des informations sur l’interface sous Windows:

Vous pouvez également récupérer les informations que vous recherchez en utilisant: WSAIoctl avec cette option: SIO_GET_INTERFACE_LIST

Vous ne pouvez pas faire cela en standard C ++.

Je poste ceci parce que c’est la seule réponse correcte. Votre question demande comment le faire en C ++. Eh bien, vous ne pouvez pas le faire en C ++. Vous pouvez le faire dans Windows, POSIX, Linux, Android, mais toutes ces solutions sont spécifiques au système d’exploitation et ne font pas partie du standard de langage.

Le standard C ++ n’a pas de couche réseau du tout.

Je suppose que vous avez cette fausse hypothèse que C ++ Standard définit la même étendue de fonctionnalités que les autres normes de langage, Java. Bien que Java puisse avoir une mise en réseau intégrée (et même une infrastructure graphique) dans la bibliothèque standard du langage, C ++ ne le fait pas.

Bien qu’il existe des API et des bibliothèques tierces pouvant être utilisées par un programme C ++, cela ne signifie pas que vous pouvez le faire en C ++.

Voici un exemple pour clarifier ce que je veux dire. Vous pouvez ouvrir un fichier en C ++ car il contient une classe fstream dans sa bibliothèque standard. Ce n’est pas la même chose que l’utilisation de CreateFile() , qui est une fonction spécifique à Windows et disponible uniquement pour WINAPI.

Notez également que “l’adresse IP locale” pourrait ne pas être une chose particulièrement unique. Si vous êtes sur plusieurs réseaux physiques (filaire + sans fil + bluetooth, par exemple, ou un serveur avec beaucoup de cartes Ethernet, etc.) ou si vous disposez d’une configuration d’interfaces TAP / TUN, votre machine peut facilement disposer d’une multitude d’interfaces.

Comment obtenir l’adresse IP de la machine locale sur le réseau semble bien décrire la solution …

Winsock spécifique:

 // 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(); 

de torial: Si vous utilisez winsock, voici un moyen: http://tangentsoft.net/wskfaq/examples/ipaddr.html

Comme pour la partie sous-réseau de la question; il n’y a pas de moyen indépendant de la plate-forme pour récupérer le masque de sous-réseau car l’API de socket POSIX (que tous les systèmes d’exploitation modernes implémentent) ne le spécifie pas. Vous devrez donc utiliser la méthode disponible sur la plate-forme que vous utilisez.

J’ai pu le faire en utilisant le service DNS sous VS2013 avec le code suivant:

 #include  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); 

J’ai dû append Dnsapi.lib en tant que dépendance addictive dans l’option de l’éditeur de liens.

Référence ici .

Vous ne pouvez pas simplement envoyer à INADDR_BROADCAST ? Certes, cela va envoyer sur toutes les interfaces – mais c’est rarement un problème.

Sinon, ioctl et SIOCGIFBRDADDR devraient vous donner l’adresse sur * nix et WSAioctl et SIO_GET_BROADCAST_ADDRESS sur win32.

Dans DEV C ++, j’ai utilisé du C pur avec WIN32, avec ce morceau de code:

 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; 

Lorsque je clique sur le bouton “show ip”, cela fonctionne. Mais la deuxième fois, le programme se ferme (sans avertissement ni erreur). Quand je fais:

 //WSACleanup(); 

Le programme ne quitte pas, même en cliquant sur le même bouton plusieurs fois avec la vitesse la plus rapide. Donc, WSACleanup () peut ne pas fonctionner correctement avec Dev-C ++.

Je suggère mon code.

 DllExport void get_local_ips(boost::container::vector& 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); wssortingng wstr(ipwstr); if (wstr != "0.0.0.0") ips.push_back(wstr); } } free(adapters); adapters = NULL; }