ابزار کاربر

ابزار سایت


c-socket-programming:getaddrinfo

تابع ()getaddrinfo

معمولا از تابع ()getaddrinfo برای پر کردن استراکچر های مورد نیاز توابع دیگر یا ترجمه آدرس های اینترنتی استفاده میشود.

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int getaddrinfo(const char *restrict node,
                const char *restrict service,
                const struct addrinfo *restrict hints,
                struct addrinfo **restrict res);

void freeaddrinfo(struct addrinfo *res);

const char *gai_strerror(int errcode);


Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

getaddrinfo(), freeaddrinfo(), gai_strerror():
    Since glibc 2.22:
        _POSIX_C_SOURCE >= 200112L
    glibc 2.21 and earlier:
        _POSIX_C_SOURCE

تابع ()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 استفاده میشود :

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()
};
 
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 قابل استفاده هستند:

typedef uint32_t in_addr_t;
struct in_addr {
    in_addr_t s_addr; // that's a 32-bit int (4 bytes)
};
 
struct in6_addr {
    unsigned char   s6_addr[16];   // IPv6 address
};

در مثال زیر برای ترجمه نام اینترنتی به IP با کمک DNS ، از تابع ()getaddrinfo استفاده شده است. hints باید از قبل با memset صفر شده باشد و لااقل فیلد های ai_family و ai_socktype و ai_protocol مقدار دهی شده باشند :

// getaddrinfo.c
// gcc -std=c99 -Wall -Wextra -Werror -pedantic -o getaddrinfo getaddrinfo.c
 
#define _POSIX_C_SOURCE 200112L
 
#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";
 
    struct addrinfo hints, *res;
 
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;       
    hints.ai_socktype = SOCK_STREAM;    // defined in /usr/include/bits/socket_type.h
    hints.ai_protocol = 0;
 
    int 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 (struct addrinfo *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);
    }
 
    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

همانطور که در قسمت Feature Test Macro در manual نوشته شده برای اینکه تعریف توابع ()getaddrinfo و ()freeaddrinfo و ()gai_strerror و استراکچر های مورد نیاز، از طریق header در دسترس باشند (expose شوند) در gcc های ورژن بالاتر از 2.22 باید ماکرو زیر تعریف شود

#define _POSIX_C_SOURCE 200112L

برای بررسی کار کرد ماکرو فوق، می توان یک بار بدون ماکرو و یک بار با وجود ماکرو، از دستور زیر استفاده کنیم و در خروجی، تعریف struct addrinfo را جستجو کنیم. خواهیم دید که بدون ماکرو فوق این استراکچر تعریف نمیشود

gcc -std=c99 -E getaddrinfo.c
c-socket-programming/getaddrinfo.txt · آخرین ویرایش: 2024/06/28 13:31 توسط pejman

به جز مواردی که ذکر می‌شود، مابقی محتویات ویکی تحت مجوز زیر می‌باشند: Public Domain
Public Domain Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki