现在的位置: 首页 > 综合 > 正文

Socket的地址查询

2013年03月11日 ⁄ 综合 ⁄ 共 4219字 ⁄ 字号 评论关闭

    Socket的地址查询函数有很多, 分为主机(host), 网络(net), 协议(proto)和服务(serv), 这些函数完成各种地址查询功能. POSIX.1定义了两个新的函数: getaddrinfo和getnameinfo, 前者把主机名字和服务名字映射到一个地址, 后者将地址转换成主机名或服务器名.

    这些函数返回的网络配置信息可能存放在许多地方. 它们可以保存在静态文件中(如/etc/hosts, /etc/services等), 或者可以由命名服务器(如DNS, NIS).

    这些地址查询函数大致分为几类: 主机(host), 网络(net), 协议(proto), 服务(serv), 这几类的相关函数也是带有该类别的名字. 下面就这几类分别进行说明:

1. 主机信息查询:

struct hostent
{
    
char  *h_name;       /* name of host */
    
char **h_aliases;    /* pointer to alternate host name array */
    
int       h_addrtype; /* address type */
    
int       h_length;     /* length in bytes of address */
    
char **h_addr_list; /* pointer to array of network addresses */
    ...
    ...
}
;

 头文件: <netdb.h>

函数原型:

  • struct hostent *gethostent();
  • void sethostent(int stayopen);
  • void endhostent();

说明:

  • gethostent: 打开数据文件, 如果数据文件打开则返回文件的下一个条目.
  • sethostent: 打开文件, 如果文件已打开, 将其回绕.
  • endhostent: 关闭文件.

2. 网络名字和网络号查询:

struct netent
{
    
char     *n_name;      /* network name */
    
char    **n_aliases;    /* pointer to alternate network name array */
    
int          n_addrtype; /* address type */
    uint32_t n_net;         
/* network number */
    ...
    ...
}
;

头文件: <netdb.h>

函数原型:

  • struct netent *getnetbyaddr(uint32_t net, int type);
  • struct netent *getnetbyname(const char *name);
  • struct netent *getnetent();
  • void setnetent(int stayopen);
  • void endnetent();

3. 协议名字和协议号查询:

struct protoent
{
    
char  *p_name; /*protocol name */
    
char **p_aliases; /* pointer to alternate protocol name array */
    
int       p_proto; /* protocol number */
    ...
    ...
}
;

头文件: <netdb.h>

函数原型:

  • struct protoent *getprotobyname(const char *name);
  • struct protoent *getprotobynumber(int proto);
  • struct protoent *getprotoent();
  • void setprotoent(int stayopen);
  • void endprotoent();

4. 服务查询:

struct servent
{
    
char  *s_name;    /*service name */
    
char **s_aliases; /* pointer to alternate service name array */
    
int       s_port;      /* port number */
    
char  *s_proto;     /* name of protocol */
    ...
    ...
}
;

头文件: <netdb.h>

函数原型:

  • struct servent *getservbyname(const char *name, const char *proto);
  • struct servent *getservbyport(int port, const char *proto);
  • struct servent *getservent();
  • void setservent(int stayopen);
  • void endservent();

5. getaddrinfo函数:

  • 原型: int getaddrinfo(const char *restrict host,

const char *restrict service,

const struct addrinfo *restrict hint,

struct addrinfo **restrict res);

  • 头文件: <sys/socket.h> <netdb.h>
  • 返回值: 成功则返回0, 出错则返回非0错误代码.
  • 参数:
    • host: 主机名字. 可以是节点名或者是点分十进制表示的主机地址.
    • service: 服务名字.
    • hint: 过滤地址的模板, 仅使用ai_family, ai_flags, ai_protocol和ai_socktype字段, 剩余字段必须设为0或NULL.
    • res: 保存查询结果的指针.
  • 说明: 主机名字和服务名字可以都提供, 如果只提供一个, 另一个必须为空.

     这个函数里面涉及到一个结构:

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;             /* net in list */
    ...
    ...
}
;

getaddrinfo函数返回一个该结构的链表, 我们可以看到该结构中含有一个next成员, 这些链表结点在不用之后, 都需要用freeaddrinfo来逐个释放.

  • 原型: void freeaddrinfo(struct addrinfo *ai);
  • 头文件: <sys/socket.h> <netdb.h>

addrinfo结构中的ai_flags有以下几种值:

  • AI_ADDRCONFIG: 查询配置的地址类型(IPv4或IPv6).
  • AI_ALL: 查找IPv4和IPv6地址(仅用于AI_V4MAPPED).
  • AI_CANONNAME: 需要一个规范名(而不是别名).
  • AI_NUMERICHOST: 以数字格式返回主机地址.
  • AI_NUMERICSERV: 以端口号返回服务.
  • AI_PASSIVE: socket地址用于监听绑定.
  • AI_V4MAPPED: 如果没有找到IPv6地址, 则返回映射到IPv6格式的IPv6地址.

如果getaddrinfo失败, 不能使用perror或strerror来生成错误信息, 应该使用gai_strerror将返回的错误码转换成错误信息:

  • 原型: const char *gai_strerror(int error);
  • 头文件: <netdb.h>

6. getnameinfo函数:

  • 原型: int getnameinfo(const struct sockaddr *restrict addr, socklen_t alen,

char *restrict host, socklen_t hostlen,

char *restrict service, socklen_t servlen,

unsigned int flags);

  • 头文件: <sys/socket.h> <netdb.h>
  • 参数:
    • addr: socket地址.
    • alen: socket地址长度.
    • host: 主机名.
    • hostlen: 主机名长度.
    • service: 服务名.
    • servlen: 服务名长度.
    • flags: 指定转换的控制方式. 可以有如下几种:
      • NI_DGRAM: 服务基于数据报而非基于流.
      • NI_NAMEREQD: 如果找不到主机名字, 将其作为一个错误对待.
      • NI_NOFQDN: 对于本地主机, 仅返回完全限定域名的节点名部分.
      • NI_NUMERICHOST: 以数字形式而非名字返回主机地址.
      • NI_NUMERICSERV: 以数字形式而非名字返回服务地址(即端口号).
  • 说明: 如果host或service非空, 它(们)将指向洋长度问该len字节的缓冲区用于存储返回的名. 如果为空则不返回该名.

 以上就是socket的地址查询所有相关函数, 在以后的文章里会有带详细注释的实例代码并进行编译运行讲解.

抱歉!评论已关闭.