UNIX网络编程笔记 第十一章 名字与地址转换

只适用于IPV4的函数:
#include <netdb.h>

struct hostent *gethostbyname(const char *hostname);
//成功返回非空指针,出错返回NULL且设置h_errno

struct hostent{
    char *h_name;        //名字
    char **h_aliases;    //指向别名列表的指针
    int h_addrtype;      //AF_INET
    int h_length;        //地址长度,4(bytes)
    char **h_addr_list;  //指向地址列表的指针
}


struct hostent *gethostbyaddr(const char *addr, socklen_t len, int family);
//成功返回非空指针,出错返回NULL且设置h_errno
/*
addr参数实际上是一个in_addr结构指针
family固定为AF_INET
*/


struct servent *getservbyname(const char *servname,const char *protoname);
//成功返回非空指针,出错返回NULL

struct servent {
    char *s_name;     //名字
    char **s_aliases; //别名列表
    int s_port;       //端口号,网络字节序
    char *s_proto;    //协议名 udp tcp
}


struct servent *getservbyport(int port,const char *protoname);
IPV4和IPV6通用函数:
#include <netdb.h>

int getaddrinfo(const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result);
//成功返回0,失败非0,可使用gai_strerror(rtn)函数打印错误信息

    /*
        struct addrinfo {
            int ai_flags;           //AI_PASSIVE,AI_CANONNAME
            int ai_family;          //AF_XXX
            int ai_socktype;        //SOCK_XXX
            int ai_protocol;        //0,IPPROTO_IPV4,IPPROTO_IPV6
            socklen_t ai_addrlen;       //length of ai_addr
            char *ai_canonname;     //canonname
            struct sockaddr *ai_addr;   //addr
            struct addrinfo *ai_next;   //next
        }

        ai_flags:
        AI_PASSIVE 套接字将用于被动打开
        AI_CANONNAME 返回主机规范名
        AI_NUMBERICHOST 不做DNS转换,hostname必须是地址串,用于把字符串转换为sockaddr
        AI_NUMBERICSERV 不做DNS转换,service必须是十进制端口号,用于把端口号转换到sockaddr中
        AI_V4MAPPED
        AI_ALL
        AI_ADDRCONFIG
    */


void freeaddrinfo(struct addrinfo *ai);
//getaddrinfo返回的result要手动释放


int getnameinfo(const struct sockaddr *sockaddr,socklen_t addrlen,char *host,socklen_t hostlen,char *serv,socklen_t servlen,int flags);
//成功返回0,出错返回非0
/*
    如果不想返回host或serv,就把hostlen或servlen设置为0

    flags:
    NI_DGRAM          表明使用数据报服务
    NI_NAMEREQD       若不能从地址解析出名字则返回错误
    NI_NOFQDN         只返回FQDN的主机名部分(第一个点号之前的部分)
    NI_NUMERICHOST    以数字串格式返回主机字符串
    NI_NUMERICSCOPE   以数字串格式返回范围标识
    NI_NUMERICSERV    以数字串格式返回服务端口
*/
//mydns.c

#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <poll.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
#include <sys/select.h>
#include <time.h>

#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))


int main(int argc, char **argv){

    if(argc < 3){
        printf("usage: mydns -h hostname -s 21 -f 4/6 -S dgram/stream -p 0/4/6\n");
        return 1;
    }


    char *hostname = NULL;
    char *service = NULL;
    struct addrinfo hints, *result;

    for(int i = 0; i < argc; i++){
        printf("argv%d:%s\n",i,argv[i]);
        if(i >= 2 && ((i % 2) == 0)){
            char *type = argv[i-1];
            if(strcmp(type,"-h") == 0){
                hostname = argv[i];
                printf("hostname = %s\n",hostname);
            }else if(strcmp(type,"-s") == 0){
                service = argv[i];
                printf("service = %s\n",service);
            }else if(strcmp(type, "-f") == 0){
                if(strcmp(argv[i], "4") == 0){
                    hints.ai_family = AF_INET;
                    puts("AF_INET");
                }else{
                    hints.ai_family = AF_INET6;
                    puts("AF_INET6");
                }
            }else if(strcmp(type,"-S") == 0){
                if(strcmp(argv[i],"dgram") == 0){
                    hints.ai_socktype = SOCK_DGRAM;
                    puts("SOCK_DGRAM");
                }else{
                    hints.ai_socktype = SOCK_STREAM;
                    puts("SOCK_STREAM");
                }
            }else if(strcmp(type,"-p") == 0){
                if(strcmp(argv[i],"0") == 0){
                    hints.ai_protocol = 0;
                    puts("protocol=0");
                }else if(strcmp(argv[i], "4") == 0){
                    hints.ai_protocol = IPPROTO_IPV4;
                    puts("protocol=4");
                }else{
                    hints.ai_protocol = IPPROTO_IPV6;
                    puts("protocol=6");
                }
            }else{
                printf("param %s is invalid\n",type);
            }
        }
    }

    int n = getaddrinfo(hostname,service,&hints,&result);
    if(n != 0){
        printf("getaddrinfo error:%s\n",gai_strerror(n));
        return 1;
    }

    struct addrinfo *ressave = result;
    n = 0;
    do{
        char addr[140];
        char serv[30];
        addr[0] = 0;
        serv[0] = 0;
        int rtn = getnameinfo(result->ai_addr,result->ai_addrlen,addr,140,serv,30,NI_NUMERICSERV);
        if(rtn != 0){
            printf("getnameinfo error:%s\n",gai_strerror(rtn));
        }
        printf("###### address %d info ########\n",n);
        printf("cannoname:%s\n",result->ai_canonname);
        printf("addr:%s:%s\n",addr,serv);

        result = result->ai_next;
        n++;
    }while(result != NULL);

    freeaddrinfo(ressave);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值