این یک نگارش قدیمی از این مطلب است!
تابع ()getaddrinfo
معمولا از تابع ()getaddrinfo برای پر کردن استراکچر های مورد نیاز توابع دیگر یا ترجمه آدرس های اینترنتی استفاده میشود.
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo **res);
void freeaddrinfo(struct addrinfo *res);
const char *gai_strerror(int errcode);
تابع ()getaddrinfo یک node به عنوان Internet Host یک service و یک struct addrinfo به نام hints وارد میکند و نتیجه را در یک linked-list از نوع struct addrinfo به نام res باز میگرداند. خروجی این تابع در تابع ()bind و تابع ()connect قابل استفاده است.
تابع ()freeaddrinfo برای آزاد کردن حافظه اختصاص داده شده به linked-list و از تابع ()gai_strerror برای کنترل error ها استفاده میشود.
استراکچر addrinfo :
struct addrinfo { int ai_flags; // AI_PASSIVE, AI_CANONNAME, etc. int ai_family; // AF_INET, AF_INET6, AF_UNSPEC int ai_socktype; // SOCK_STREAM, SOCK_DGRAM int ai_protocol; // use 0 for "any" size_t ai_addrlen; // size of ai_addr in bytes struct sockaddr *ai_addr; // struct sockaddr_in or _in6 char *ai_canonname; // full canonical hostname struct addrinfo *ai_next; // linked list, next node };
در استراکچر فوق متغییر ai_addr از نوع *struct sockaddr است :
struct sockaddr { unsigned short sa_family; // address family, AF_xxx char sa_data[14]; // 14 bytes of protocol address };
استراکچر فوق به تنهایی قابل استفاده نیست و تنها با cast شدن از struct sockaddr_in یا struct sockaddr_in6 استفاده میشود :
// man 7 ip struct sockaddr_in { short int sin_family; // Address family, AF_INET unsigned short int sin_port; // Port number, Network Byte Order with htons() struct in_addr sin_addr; // Internet address unsigned char sin_zero[8]; // Same size as struct sockaddr, set to zero with memset() }; // man 7 ipv6 struct sockaddr_in6 { u_int16_t sin6_family; // address family, AF_INET6 u_int16_t sin6_port; // port number, Network Byte Order u_int32_t sin6_flowinfo; // IPv6 flow information struct in6_addr sin6_addr; // IPv6 address u_int32_t sin6_scope_id; // Scope ID };
در استراکچر های فوق struct in_addr و struct in6_addr وجود دارند که در تابع ()inet_ntop و تابع ()inet_pton قابل استفاده هستند:
// man 7 ip // man 3 inet // (IPv4 only--see struct in6_addr for IPv6) // Internet address (a structure for historical reasons) typedef uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; // that's a 32-bit int (4 bytes) }; // man 7 ipv6 struct in6_addr { unsigned char s6_addr[16]; // IPv6 address };
در مثال زیر برای ترجمه نام اینترنتی به IP با کمک DNS ، از تابع ()getaddrinfo استفاده شده است. hints باید از قبل با memset صفر شده باشد و لااقل فیلد های ai_family و ai_socktype و ai_protocol مقدار دهی شده باشند :
// getaddrinfo.c // gcc -Wall -Wextra -Werror -pedantic -o getaddrinfo getaddrinfo.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> int main() { char *node = "www.yahoo.com"; int errcode; struct addrinfo hints, *res ,*p; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; errcode = getaddrinfo(node, NULL, &hints, &res); if (errcode != 0) { fprintf(stderr, "getaddrinfo() error: %s\n", gai_strerror(errcode)); exit(EXIT_FAILURE); } printf("\nInternet addresses of %s :\n\n", node); for (p = res; p != NULL; p = p->ai_next) { char *ipver, ipstr[INET6_ADDRSTRLEN]; void *addr; if (p->ai_family == AF_INET) { ipver = "IPv4"; struct sockaddr_in *ipv4 = (struct sockaddr_in *)(p->ai_addr); addr = &(ipv4->sin_addr); } else if (p->ai_family == AF_INET6) { ipver = "IPv6"; struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)(p->ai_addr); addr = &(ipv6->sin6_addr); } else { printf("Unknown\n"); } inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr); printf(" %s: %s\n", ipver, ipstr); } printf("\n"); freeaddrinfo(res); return 0; }
خروجی
Internet addresses of www.yahoo.com : IPv4: 87.248.100.216 IPv4: 87.248.100.215 IPv6: 2a00:1288:110:c305::1:8000 IPv6: 2a00:1288:110:c305::1:8001
