2017-06-26 4 views
1

J'écris un programme qui vérifierait si un port sur url ou ip donné est ouvert ou non. Afin d'obtenir l'adresse IP de l'URL donnée, j'utilise gethostbyname(). Lorsque vous essayez de rechercher l'adresse de localhost, elle renvoie la valeur correcte, mais en essayant de rechercher l'adresse d'un hôte distant, elle échoue généralement et renvoie une adresse IP avec des nombres négatifs. Par exemple:gethostbyname() renvoie une structure avec l'adresse négative

/test.out google.com 
ip: -40.58.-42.78 

/test.out reddit.com 
ip: -105.101.-127.-116 

./test.out facebook.com 
ip: 31.13.84.36 

Bizarrement, le dernier fonctionne. Voici mon code:

#include <stdio.h> 
#include <stdlib.h> 
#include <netdb.h> 

int main(int argc, char **argv) 
{ 
    struct hostent *he; 
    struct in_addr **addr_list; 

    if ((he = gethostbyname(argv[1])) == NULL) { 
     herror("gethostbyname"); 
     return 1; 
    } 

    printf("ip: "); 
    for (int i = 0; i < he->h_length; i++) { 
     printf("%d", he->h_addr_list[0][i]); 
     if (i != he->h_length - 1) printf("."); 
    } 
    printf("\n"); 
} 

Aussi, pourquoi est le type de h_addr_listchar **? Ne devrait-il pas être un nombre entier, ou même mieux un non signé?

+0

Vous essayez probablement d'imprimer des chaînes. –

+2

Utilisez la fonction 'inet_ntoa' pour convertir l'adresse en chaîne, plutôt que de la coder vous-même. – Barmar

Répondre

4

Les composants d'une adresse IP sont des octets non signés mais, dans un struct hostent, ils sont stockés sous la forme char (c'est-à-dire signés). Cela signifie que les valeurs 128 .. 255 sont interprétées comme des nombres négatifs.

Vous les imprimez en utilisant le format %d qui imprime les valeurs telles qu'elles sont signées car c'est ainsi qu'elles les reçoivent. Convertir les valeurs à unsigned char (ou unsigned int si vous préférez) lorsque vous les passez à printf():

printf("%d", (unsigned char)he->h_addr_list[0][i]); 

Vous pouvez également utiliser %u au lieu de %d (il traite comme unsigned les valeurs qu'il reçoit), mais vous avez encore besoin convertir les valeurs de passer à elle à unsigned :

printf("%u", (unsigned char)he->h_addr_list[0][i]); 

une autre option est de forcer l'utilisation printf() seulement l'octet le moins significatif de la val il obtient et imprime comme non signé, en utilisant "%hhu". Cependant, cela ressemble plus à un hack qu'à la solution correcte.


Sans la conversion, car printf() est un variadic function, les valeurs qui lui sont transmis comme arguments (he->h_addr_list[0][i]) sont promus de (signed) char à (signed) int. L'utilisation de "%u" pour les imprimer produit de très grands nombres au lieu de nombres négatifs pour les composants dont la taille est supérieure à 127.

+1

La signature de 'char' dépend du compilateur. –

2

Cette réponse est spécifiquement le type de h_addr_list. Dans l'esprit des anciens programmeurs BSD qui ont inventé gethostbyname, il allait être utilisé pour rechercher toutes sortes d'adresses réseau, pas seulement les adresses IP. C'est pourquoi il a aussi un h_addrtype. L'interprétation de h_addr_list[n] dépendrait de h_addrtype. Pour h_addrtype==AF_INET, une adresse est le format d'adresse IP de 4 octets que vous connaissez. Pour d'autres types d'adresses, cela peut être d'autres choses. Il faut comprendre le type char ** de h_addr_list comme "tableau dynamiquement alloué de tampons opaques". Il aurait pu être void ** mais void n'avait pas encore été inventé.Il s'est avéré que IPv4 est devenu le seul protocole de réseau dont tout le monde se souciait, jusqu'à ce qu'IPv6 arrive, puis il a été décidé de remplacer entièrement l'interface de recherche d'hôte (voir getaddrinfo). Il y a donc eu peu d'occasions de voir un non-AF_INETh_addrtype dans la nature.