ابزار کاربر

ابزار سایت


c-socket-programming:getaddrinfo

این یک نگارش قدیمی از این مطلب است!


تابع ()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
c-socket-programming/getaddrinfo.1718738786.txt.gz · آخرین ویرایش: 2024/06/18 22:56 توسط pejman

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