求助:使用C语言getaddrinfo获取google.com的IP地址失败
Hey there, I get it—trying to fetch a domain's IP address can feel frustrating when most tutorials fixate on local socket pairs (which are for inter-process communication on the same machine, by the way) and even trusted resources don't work out of the box for you. Let's break down what's wrong with your code and fix it step by step.
What's Going Wrong in Your Code
There are three key issues causing the garbage output and segmentation fault:
No error checking for
getaddrinfo
This function returns a non-zero error code if it fails (e.g., DNS resolution fails, invalid parameters). If you skip checking this, you might end up operating on a NULLrespointer, which leads to crashes.Broken loop traversal
Your for loop initializesi = resbut then usesres = res->ai_nextto advance the pointer, while the loop condition checksi != 0. This means you're not actually usingito traverse the list, and eventuallyresbecomes NULL—accessingres->ai_addrat that point triggers a segmentation fault.Directly printing
sa_datais incorrect
Thesa_datafield instruct sockaddrstores binary address data, not human-readable strings. You need to convert this binary data to a readable IP format using functions likeinet_ntop, and first cast the genericsockaddrto the correct IPv4 or IPv6 struct based on the address family.
Fixed Code with Explanations
Here's a corrected version that properly resolves google.com and prints its IP addresses:
#include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <netdb.h> #include <string.h> #include <arpa/inet.h> int main(void) { struct addrinfo hints, *res, *current_addr; int status; char ip_buffer[INET6_ADDRSTRLEN]; // Buffer big enough for IPv6 addresses // Initialize hints to specify what kind of addresses we want memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // Accept both IPv4 and IPv6 hints.ai_socktype = SOCK_STREAM; // We're looking for TCP addresses (matches port 443) // Call getaddrinfo and check for errors if ((status = getaddrinfo("google.com", "443", &hints, &res)) != 0) { fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(status)); return 1; } printf("IP addresses for google.com:\n\n"); // Traverse the linked list of addresses for (current_addr = res; current_addr != NULL; current_addr = current_addr->ai_next) { void *raw_ip; const char *ip_version; // Cast to the correct struct based on address family if (current_addr->ai_family == AF_INET) { struct sockaddr_in *ipv4 = (struct sockaddr_in *)current_addr->ai_addr; raw_ip = &(ipv4->sin_addr); ip_version = "IPv4"; } else { struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)current_addr->ai_addr; raw_ip = &(ipv6->sin6_addr); ip_version = "IPv6"; } // Convert binary IP to human-readable string inet_ntop(current_addr->ai_family, raw_ip, ip_buffer, sizeof(ip_buffer)); printf(" %s: %s\n", ip_version, ip_buffer); } // Free the memory allocated by getaddrinfo (critical to avoid leaks!) freeaddrinfo(res); return 0; }
Key Improvements:
hintsstruct: Tellsgetaddrinfoexactly what type of addresses we need (TCP, IPv4/IPv6) instead of letting it return arbitrary address types.- Error handling: Checks if
getaddrinfofails and prints a meaningful error message usinggai_strerror. - Proper list traversal: Uses
current_addrto iterate through the linked list without modifying the originalrespointer, preventing null pointer access. - IP conversion: Uses
inet_ntopto convert binary address data to a readable string, with logic to handle both IPv4 and IPv6. - Memory cleanup: Calls
freeaddrinfoto release the memory allocated bygetaddrinfo—always remember this to avoid memory leaks!
Quick Note on Local Sockets
You mentioned confusion about tutorials focusing on local client/server sockets: those use the AF_UNIX (or AF_LOCAL) address family, and they're for communication between processes on the same machine (e.g., a local database and a desktop app, or system services talking to each other). They don't involve network communication or DNS resolution, which is why they don't help with your goal of fetching google.com's IP.
内容的提问来源于stack exchange,提问作者RaspberMan

