Contents ...
udn網路城邦
linux名字與地址轉換
2015/07/07 13:08
瀏覽134
迴響0
推薦0
引用0
在網絡中,主機都是用IP地址標示的;但是,出於很多理由,我們應該使用名字,而非純數字:名字比較好記,數值地址可以變動但名字可以不變(如域名),隨著往IPV6上轉移,地址變得很長,數值書寫容易出錯等等。本文示例Linux幾個處理名字與地址轉換的函數的使用:

#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <getopt.h>

struct option g_opts[] = {
    {"host", required_argument, NULL, 'h'},
    {"server", required_argument, NULL, 's'},
    {"protocol", required_argument, NULL, 'p'},
    {"help", no_argument, NULL, 'H'}
};

/* struct hostent
   {
    char *h_name;
    char **h_aliases;
    int h_addrtype;
    int h_length;
    char **h_addr_list;
    #define h_addr h_addr_list[0]
   };
 */

/*
struct servent {
    char *s_name;    //official service name
    char **s_aliases;    //alias list
    int s_port;         //port number, network-byte order
    char *s_proto;        // protocol to use
*/
void showUsage()
{
    printf("Usage:\n\tidns -h [ipstr/hostname]\n\t -s [servname/servport] -g [protocol]\n");
}

static void printServent(struct servent *sptr)
{
    char **pptr;

    printf("Server name: %s\n", sptr->s_name);

    pptr = sptr->s_aliases;
    while (pptr && *pptr != NULL)
    {
        printf("\taliases: %s\n", *pptr);
        pptr++;
    }

    printf("\tport: %d\n", ntohs(sptr->s_port));
    printf("\tproto: %s\n", sptr->s_proto);
}

static void printHostent(struct hostent *hptr)
{
    char str[33] = { 0, };
    char **pptr;

    if (NULL == hptr)
        return;

    printf("Official hostname:%s\n", hptr->h_name);

    for (pptr = hptr->h_aliases; *pptr != NULL; pptr++)
        printf("alias:%s\n", *pptr);

    switch (hptr->h_addrtype)
    {
    case AF_INET:
    case AF_INET6:
        pptr = hptr->h_addr_list;
        for (; pptr && *pptr != NULL; pptr++)
            printf("address: %s\n", inet_ntop(hptr->h_addrtype, *pptr, str, 32));
        break;
    default:
        printf("Unknow address type\n");
        break;
    }

}

static void printHerror(int pError)
{
    switch (pError)
    {
    case HOST_NOT_FOUND:
        printf("host not found!\n");
        break;
// case NO_ADDRESS:
// case NO_DATA:printf("112\n");break;
    case NO_RECOVERY:
        printf("no recovery!\n");
        break;
    case TRY_AGAIN:
        printf("try again\n");
        break;
    default:
        printf("unknow error type:%d\n", pError);
        return;
    }
}

void iGethostbyname_common(char *name)
{
    struct addrinfo *answer, hint, *curr;
    char ipstr[16];
    int ret;

    memset(&hint, 0, sizeof(hint));
    hint.ai_flags = AI_CANONNAME;

    ret = getaddrinfo(name, NULL, &hint, &answer);
    if (ret != 0)
    {
        fprintf(stderr, "getaddrinfo fail: %s\n", gai_strerror(ret));
        exit(1);
    }

    for (curr = answer; curr != NULL; curr = curr->ai_next)
    {
        printf("Host name: %s\n", curr->ai_canonname == NULL ? "" : curr->ai_canonname);

        inet_ntop(AF_INET, &(((struct sockaddr_in *)(curr->ai_addr))->sin_addr), ipstr, 16);
        printf("Addr: %s\n", ipstr);
    }

    freeaddrinfo(answer);
}

void iGethostbyname_ipv4(char *name)
{
    struct hostent *hptr;
    if ((hptr = gethostbyname(name)) == NULL)
    {
        printf("gethostbyname fail for host:%s\n", name);
        return;
    }
    printHostent(hptr);
}

void iGethostbyaddr_ipv4(char *addr)
{
    struct hostent *hptr;
    in_addr_t nip;
    int tryTimes = 3;

    nip = inet_addr(addr);

  L_TRY_AGAIN:
    if ((hptr = gethostbyaddr(&nip, 4, AF_INET)) == NULL)
    {
        if (h_errno == TRY_AGAIN && tryTimes > 0)
        {
            tryTimes--;
            goto L_TRY_AGAIN;
        }

        printf("Fail to get host by addr<%s>: ", addr);
        printHerror(h_errno);
        return;
    }
    printHostent(hptr);
}

void iGetservbyname(char *name, char *proto)
{
    struct servent *sptr;

    if ((sptr = getservbyname(name, proto)) == NULL)
    {
        printf("Can NOT find server with name:%s and protocol:%s\n", name, proto);
        return;
    }

    printServent(sptr);

}

void iGetservbyport(int port, char *proto)
{
    struct servent *sptr;

    if ((sptr = getservbyport(htons(port), proto)) == NULL)
    {
        printf("Can NOT find server with port:%d and protocol:%s\n", port, proto);
        return;
    }
    printServent(sptr);
}

char g_buf[64] = { 0, };
char g_proto[16] = { 0, };

int main(int argc, char **argv)
{
    int opt;
    int cmdType = 0;

    int temp = 0;

    if (argc < 2)
    {
        showUsage();
        return 0;
    }

    while ((opt = getopt_long(argc, argv, "s:h:p:", g_opts, NULL)) != -1)
    {
        switch (opt)
        {
        case 's':
            strcpy(g_buf, optarg);
            cmdType = 1;
            break;
        case 'h':
            strcpy(g_buf, optarg);
            cmdType = 2;
            break;
        case 'p':
            strcpy(g_proto, optarg);
            break;
        case 'H':
            showUsage();
            break;
        default:
            showUsage();
            return;
        }
    }

    if (cmdType == 2 && (inet_addr(g_buf)) == INADDR_NONE)
    {
        iGethostbyname_ipv4(g_buf);
    }
    else if (cmdType == 2)
    {
        iGethostbyaddr_ipv4(g_buf);
    }
    else if (cmdType == 1)
    {
        temp = atoi(g_buf);
        if (temp > 0)
            iGetservbyport(temp, g_proto);
        else
            iGetservbyname(g_buf, g_proto);
    }
    else
        showUsage();

    return 0;
}

限會員,要發表迴響,請先登入