http://beej.us/guide/bgnet/output/html/multipage/gethostbynameman.html
http://baike.baidu.com/link?url=3qVTFgQmU8MMzq33GlJwPwQkJr8lKZDVLAKNOQfA_GEytnp5EPc3E9gnTwyaL0WqT5oJDqTjf9rY1JoTMrLUvq
gethostbyname, gethostbyaddr是不可重入函数;已经被getaddrinfo, getnameinfo替代。
http://beej.us/guide/bgnet/output/html/multipage/getaddrinfoman.html
http://baike.baidu.com/view/6757218.htm
The getaddrinfo(3) function combines the functionality provided by the getipnodebyname(3), getipnodebyaddr(3), getservbyname(3), and getservbyport(3)
functions into a single interface. The thread-safe getaddrinfo(3) function creates one or more socket address structures that can be used by the bind(2)
and connect(2) system calls to create a client or a server socket. 线程安全,融合了多个函数的功能。
int getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo **res);
struct addrinfo {
int ai_flags; -- 按位赋值
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *ai_next;
};
- node或service参数最多可能有一个为NULL。
- node 要么为点分式地址(dotted-decimal format for IPv4, hexadecimalformat for IPv6) 要么为主机名。
- 如果hints中ai_flags设置了AI_NUMERICHOST,则node必须为数字地址;
- service为端口号或者端口名。如果不为空,为端口名,则必须可以解析,通过/etc/services。
- 如果ai_flags设置了AI_CANONNAME,则char *ai_canonname存储了第一个地址,相当于快捷方式?
- 如果node为null,但没有设置AI_PASSIVE,则返回回环地址,用于本地服务;
- 如果node为null,但设置AI_PASSIVE,则返回所有地址,相当于bind(INADDR_ANY)。
- 根据node和service查找到对应的addr info。如果此信息被connect调用,则表示这是被监听对象;而监听者可以通过node里面设置。node如果是fe80这种IP V6地址,必须接%eth来指定接口,则监听者就是这个local IP;如果是raw socket,则监听端口就是hints里面的 ai_protocol。 getaddrinfo() supports the address%scope-id notation for specifying the IPv6 scope-ID.
// code for a server waiting for connections
// namely a stream socket on port 3490, on this host's IP
// either IPv4 or IPv6.
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv;
memset(&hints, 0, sizeof hints);--- 必须先清零再使用
hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP address ------- 此情况下,第一个参数可以为null,则返回所有IP,相当于bind(INADDR_ANY)。
if ((rv = getaddrinfo(NULL, "3490", &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(1);
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) { ---------------------------------使用实例:可以参考gsoap的tcp_connect,soap_bind等函数。
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("socket");
continue;
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { ------ 尽管返回多个ip,但有些可能会失败,所以需要尝试
close(sockfd);
perror("bind");
continue;
}
break; // if we get here, we must have connected successfully
}
if (p == NULL) {
// looped off the end of the list with no successful bind
fprintf(stderr, "failed to bind socket\n");
exit(2);
}
freeaddrinfo(servinfo); // all done with this structure ------- 必须调用,否则内存泄露
getaddrinfo() supports the address%scope-id notation for specifying the IPv6 scope-ID. ----------- 如ipv6%eth0,即指定接口。