问题
I am trying to create a simple program that gets the ip address given a certain hostname:
My code snipped is attached below:
#include<stdio.h>
#include<stdlib.h>
#include<stdio.h>
#include<netdb.h>
#include<sys/socket.h>
#include<errno.h>
#include<arpa/inet.h>
#include<string.h>
#include<unistd.h>
int main(int argc, char *argv[]) {
if(argc<2){
printf("Please provide a hostname.\n");
exit(1);
}
char *hostname = argv[1];
char ip[100];
get_ip(hostname,ip);
printf("%s resolved to %s\n",hostname,ip);
}
int get_ip(char *hostname,char *ip){
struct sockaddr_in *h;
int sockfd;
struct addrinfo hints, *servinfo,*res;
struct addrinfo *iter;
int rv;
memset(&hints,0,sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if((rv = getaddrinfo(hostname,"http",&hints, &res))!=0){
fprintf(stderr, "getaddrinfo %s\n",gai_strerror(rv));
return 1;
}
for(iter=res;iter != NULL;iter=iter->ai_next){
printf("%p\n",iter->ai_next);
h=(struct sockaddr_in *)iter->ai_addr;
strcpy(ip,inet_ntoa(h->sin_addr));
printf("%s\n",ip);
}
freeaddrinfo(res);
return 0;
}
I enter in the following arguments:
gcc get_ip_addr.c -o get_ip_addr;
./get_ip_addr google-public-dns-b.google.com
This results in:
0x2475330
8.8.4.4
(nil)
0.0.0.0
When i remove the "http" and &hints and set them to NULL I get the following results:
0x1b63310
8.8.4.4
0x1b63360
8.8.4.4
0x1b633b0
8.8.4.4
0x1b63410
0.0.0.0
0x1b63470
0.0.0.0
(nil)
0.0.0.0
So when I set the service and hints to NULL the getaddrinfo returns multiple possible results I don't understand why I am getting multiple ip addresses instead of just getting one ip address? Any help would be greatly appreciated! Thanks!
回答1:
By setting the service
and hints
field to NULL
, you are asking getaddrinfo
to return all possible addresses, which includes IP and IPv6, with different socket types, what you output is just the dot representation of ip address, and that's only part of the entire address structure getaddrinfo
returned. If you look carefully the returned addresses, you will notice that each address is actually different. For example, following program output 6 addresses in total:
int main(int argc, char *argv[])
{
struct addrinfo *result, *rp;
int s;
s = getaddrinfo("google-public-dns-b.google.com", NULL, NULL, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
char addr[1024];
for (rp = result; rp != NULL; rp = rp->ai_next) {
printf("flags: 0x%x\tfamily: %d\tsocktype: %d\tprotocol: %d\n",
rp->ai_flags,
rp->ai_family,
rp->ai_socktype,
rp->ai_protocol);
s = getnameinfo(rp->ai_addr, rp->ai_addrlen, addr, sizeof addr, NULL, 0, NI_NUMERICHOST);
if (s != 0) {
printf("getnameinfo error:%d\n", s);
continue;
}
printf("addr: %s\n", addr);
}
freeaddrinfo(result);
}
$ ./a.out
flags: 0x28 family: 2 socktype: 1 protocol: 6
addr: 8.8.4.4
flags: 0x28 family: 2 socktype: 2 protocol: 17
addr: 8.8.4.4
flags: 0x28 family: 2 socktype: 3 protocol: 0
addr: 8.8.4.4
flags: 0x28 family: 10 socktype: 1 protocol: 6
addr: 2001:4860:4860::8844
flags: 0x28 family: 10 socktype: 2 protocol: 17
addr: 2001:4860:4860::8844
flags: 0x28 family: 10 socktype: 3 protocol: 0
addr: 2001:4860:4860::8844
As you can see, each address returned are different, in terms of combination of address, family, socktype and protocol.
If you would like to return one specific type of address, use hints
to restrict the returned addresses to what you want.
Each data field explained:
Family:
#define PF_INET 2 /* IP protocol family. */
#define PF_INET6 10 /* IP version 6. */
#define AF_INET PF_INET
#define AF_INET6 PF_INET6
Socktypes:
enum __socket_type
{
SOCK_STREAM = 1, /* Sequenced, reliable, connection-based
byte streams. */
SOCK_DGRAM = 2, /* Connectionless, unreliable datagrams
of fixed maximum length. */
SOCK_RAW = 3, /* Raw protocol interface. */
....
}
Protocols:
enum {
IPPROTO_IP = 0, /* Dummy protocol for TCP */
IPPROTO_TCP = 6, /* Transmission Control Protocol */
IPPROTO_UDP = 17, /* User Datagram Protocol */
}
Another issue, you were see "0.0.0.0" in your output because you are using inet_ntoa
on IPv6 address while this function only support IPv4, and thus it has been deprecated, you should consider using inet_ntop
or getnameinfo
which supports both address families.
来源:https://stackoverflow.com/questions/40782933/why-are-there-multiple-results-from-getaddrinfo