《网络编程》套接字地址与名字转换

前言

        在套接字编程中。我们常常使用数字的 IP 地址和port号进程编程,可是我们寻常所熟悉的是一些便于记忆的字符名字,要使这样的名字可以为套接字操作函数识别,所以这两者之间必须存在着某种转换关系。本节介绍的是 【主机名地址】 和 【服务名port号】 之间的转换。

在 Unix 系统中。能够使用函数 gethostbyname、gethostbyaddr 实现【主机名 与 地址】之间的转换;能够使用函数 getservbyname、getservbyport 实现 【服务名 与 port号】 之间的转换。可是前面这些函数仅仅适合在 IPv4 域里面,若要在 IPv4 和 IPv6 实现这些功能。则能够使用 getaddrinfo 函数。有关这些函数在套接字编程中的使用可在前面文章查看《基于套接字编程

主机名地址 之间的转换

gethostbyname 与  gethostbyaddr 函数

/* 主机名与地址之间转换 */

/*
 * 函数功能:主机名与地址之间转换。
 * 返回值:若成功则返回主机结构指针。若出错则返回NULL;
 * 函数原型:
 */
#include <netdb.h>

struct hostent *gethostbyname(const char *hostname);//将主机名转换为数字地址。
struct hostent *gethostaddr(const char *addr, size_t len, int family);//将数字地址转换为主机名。

/* 函数功能:获取主机信息;
 * 函数原型:
 */
struct hostent *gethostent(void);/* 获取主机信息。并返回hostent结构指针 */
void sethostent(int stayopen);/* 设置主机信息 */
void endhostent(void);
/*
 * 说明:
 * 若主机数据文件没有打开。gethostent会打开它,该函数返回文件的下一条目;
 * 函数sethostent会打开文件。若文件已打开,那么将其回绕;
 * 函数endhostent将关闭文件。
 * 当中hostent结构至少包括例如以下成员数据:
 */
struct hostent
{
    char    *h_name;        /* official name of host */
    char    **h_aliases;    /* pointer to alternate host name array */
    int     h_addrtype;     /* address type: AF_INET */
    int     h_length;       /* length in bytes of address: 4 */
    char    **h_addr_list;  /* pointer to array of IPv4 address */
};

        上面的函数若成功调用。则会返回一个指向 hostent 结构的指针,若出错则返回 NULL,且设置全局变量 h_error 为对应值。一般的 socket 系统调用都将错误信息存储在全局变量 error 中。可是和主机 host 有关的系统调用。则将错误信息存储在 h_error 中,它的取值例如以下:

  1. HOST_NOT_FOUND:找不到主机。
  2. TRY_AGAIN:重试;
  3. NO_RECOVERY:不可修复性错误;
  4. NO_DATA:指定的名字有效,可是没有记录。
当中,hostent 结构信息之间关系例如以下图所看到的:

《网络编程》套接字地址与名字转换

服务名port号 之间的转换

getservbyname 与 getservbyport 函数 

/* 服务名与端口号之间的转换 */
/*
 * 函数功能:服务名与端口号之间的转换;
 * 返回值:若成功则返回指针,若出错则返回NULL。
 * 函数原型:
 */
#include <netdb.h>
struct servent *getservbyname(const char *servname, const char *protoname);
struct servent *getservbyport(int port, const char *protoname);
struct servent *getservent(void);

void setservent(int stayopen);
void endservent(void);
/*
 * protoname參数若为空,则返回取决与实现,若为非空。则指定协议名称。
 *
 * 当中servent 结构至少包括下面成员:
 */
struct servent
{
    char    *s_name;        /* official service name */
    char    **s_aliases;    /* pointer to alternate service name array */
    int     s_port;         /* port number */
    char    *s_proto;       /* name of protocol */
};

下面是採用上面函数编写的client程序:



【地址 与 主机名】 和 【服务名 与 port号】之间的转换

getaddrinfo 函数

/* IPv6、IPv4 都可使用 */
/*
 * 函数功能:将 服务名与port号 和 主机名与地址 之间转换。
 * 返回值:若成功则返回0。若出错则返回非0错误编码;
 * 函数原型:
 */
#include <netdb.h>
#include <sys/socket.h>
int getaddrinfo(const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result);

void freeaddrinfo(struct addrinfo *ai);/* 把从getaddrinfo函数动态分配的成员结构内存返回给系统,參数ai是由函数getaddrinfo返回的第一个addrinfo结构 */

const char *gai_strerror(int error);//若getaddrinfo出错时,错误消息仅仅能由该函数输出;

/*
 * 说明:
 * 该函数须要提供主机名或服务名,若仅仅提供当中一个,则还有一个必须指定为NULL;
 * addrinfo是一个结构链表。其定义例如以下:
 */
struct addrinfo
{
    int         ai_flags;       /* customize behavior */
    int         ai_family;      /* address family */
    int         ai_socktype;    /* socket type */
    int         ai_protocol;    /* protocol */
    socklen_t   ai_addrlen;     /* length in bytes of address */
    struct sockaddr *ai_addr;   /* address */
    char        *ai_canonname;  /* canonical name of host */
    struct addrinfo *ai_next;   /* next in list */
};

/*
 * 函数功能:将地址转换成服务名或主机名。
 * 返回值:若成功则返回0,若出错则返回非0值。
 * 函数原型:
 */
#include <netdb.h>
#include <sys/socket.h>
int getnameinfo(const struct sockadd *addr, socklen_t alen, char * host, socklen_t hostlen,
        char * service, socklen_t servlen, unsigned int flags);

/*
 * 说明:
 * addrinfo结构成员:
 * ai_flags 取值例如以下:
 * (1)AI_PASSIVE      套接字将用于被动打开;
 * (2)AI_CANONNAME    告知getaddrinfo函数返回主机的规范名字;
 * (3)AI_NUMERICHOST  防止不论什么类型的名字到地址映射,hostname必须是一个地址串。
 * (4)AI_NUMERICSERV  防止不论什么类型的名字到服务映射。service必须是一个十进制port号数串;
 * (5)AI_V4MAPPED     若同一时候指定ai_family值为AF_INET6。若没有可用的AAAA记录,则返回与A记录相应的IPv4映射的IPv6地址;
 * (6)AI_ALL          若同一时候指定AI_V4MAPPED标志,除了返回与AAAA记录相应的IPv6地址外,还返回与A记录相应的IPv4映射的IPv6地址;
 * (7)AI_ADDRCONFIG   依照所在主机的配置选择返回地址类型。
 */


參考资料:

《Unix 网络编程》