ابزار کاربر

ابزار سایت


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";
 
    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
c-socket-programming/getaddrinfo.1718774822.txt.gz · آخرین ویرایش: 2024/06/19 08:57 توسط pejman

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