**
gethostbyname函数
**
gethostbyname 函数主要功能是从主机数据库中检索与主机名对应的主机信息。
gethostbyname函数返回一个指向宿主结构的指针——宿主结构是由Windows Sockets分配的。主机结构包含成功搜索name参数中指定的主机的结果。
如果name参数中指定的主机同时具有IPv4地址和IPv6地址,则只返回IPv4地址。gethostbyname函数只能返回name参数对应的IPv4地址。如果主机需要IPv6地址,或者主机需要IPv4和IPv6地址,则应该使用getaddrinfo函数和相关的addrinfo结构。
如果name参数指向空字符串或name为NULL,则返回的字符串与成功调用gethostname函数(本地计算机的标准主机名)返回的字符串相同。
如果name参数包含合法IPv4地址的字符串表示形式,则在主机结构中返回表示该字符串的二进制IPv4地址。主机结构的h_name成员包含IPv4地址的字符串表示形式,h_addr_list包含二进制IPv4地址。如果name参数包含IPv6地址或非法IPv4地址的字符串表示形式,那么gethostbyname函数将失败并返回WSANO_DATA。
gethostbyname函数返回的宿主结构的内存是由Winsock DLL内部从线程本地存储中分配的。无论在线程上调用gethostbyaddr或gethostbyname函数多少次,只分配和使用一个宿主结构。如果要在同一线程上对gethostbyname或gethostbyaddr函数进行额外调用,则必须将返回的宿主结构复制到应用程序缓冲区中。否则,返回值将被同一线程上后续的gethostbyname或gethostbyaddr调用覆盖。为返回的宿主结构分配的内部内存在线程退出时由Winsock DLL释放。
应用程序不应该尝试释放返回的宿主结构所使用的内存。应用程序绝不能试图修改此结构或释放其任何组件。此外,每个线程只分配该结构的一个副本,因此应用程序应该在对gethostbyname或gethostbyaddr发出任何其他函数调用之前复制所需的任何信息。
gethostbyname函数不能将IP地址字符串作为名称传递给它的参数,并将其解析为主机名。这样的请求完全被视为传递的IPv4地址或未知主机名的字符串表示形式。应用程序可以使用inet_addr将IPv4地址字符串转换为二进制IPv4地址,然后使用另一个函数gethostbyaddr将IPv4地址解析为主机名。
windows系统演示示例:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
int main(int argc, char** argv)
{
//-----------------------------------------
// 声明和初始化变量
WSADATA wsaData;
int iResult = 0;
DWORD dwError = 0;
int i = 0;
struct hostent* remoteHost = nullptr;
char* host_name = nullptr;
struct in_addr addr;
char** pAlias;
// 验证参数
#ifndef _DEBUG
if (argc != 2) {
printf("usage: %s hostname\n", argv[0]);
printf(" to return the IP addresses for the host\n");
printf(" %s www.contoso.com\n", argv[0]);
printf(" or\n");
printf(" %s IPv4string\n", argv[0]);
printf(" to return an IPv4 binary address for an IPv4string\n");
printf(" %s 127.0.0.1\n", argv[0]);
return 1;
}
#endif
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
#ifndef _DEBUG
host_name = argv[1];
#else
host_name = "www.baidu.com";
#endif
printf("Calling gethostbyname with %s\n", host_name);
remoteHost = gethostbyname(host_name);
if (remoteHost == NULL) {
dwError = WSAGetLastError();
if (dwError != 0) {
if (dwError == WSAHOST_NOT_FOUND) {
printf("Host not found\n");
return 1;
} else if (dwError == WSANO_DATA) {
printf("No data record found\n");
return 1;
} else {
printf("Function failed with error: %ld\n", dwError);
return 1;
}
}
} else {
printf("Function returned:\n");
printf("\tOfficial name: %s\n", remoteHost->h_name);
for (pAlias = remoteHost->h_aliases; *pAlias != 0; pAlias++) {
printf("\t别名 #%d: %s\n", ++i, *pAlias);
}
printf("\t地址类型: ");
switch (remoteHost->h_addrtype) {
case AF_INET:
printf(" AF_INET \n");
break;
case AF_NETBIOS:
printf(" AF_NETBIOS \n");
break;
default:
printf(" %d\n", remoteHost->h_addrtype);
break;
}
printf("\t地址长度: %d\n", remoteHost->h_length);
i = 0;
if (remoteHost->h_addrtype == AF_INET) {
while (remoteHost->h_addr_list[i] != 0) {
addr.s_addr = *(u_long*)remoteHost->h_addr_list[i++];
printf("\tIP 地址 #%d: %s\n", i, inet_ntoa(addr));
}
} else if (remoteHost->h_addrtype == AF_NETBIOS) {
printf("返回 NETBIOS 地址 \n");
}
}
return 0;
}
输出结果: