这里实现域名<— —> 服务器的双向访问

  • gethostbyname:已知域名,查看 IP 地址
  • gethostbyaddr:通过 IP 地址,查看其对应的域名。

注意:一个 IP 地址可以对应多个域名。

gethostbyname 利用域名获取 IP 地址

  1. #include <winsock2.h>
  2. struct hostent* gethostbyname(const char *name);
  3. // 成功时返回 hostent 结构体变量地址值
  4. // 失败时返回 NULL 指针

这个函数使用的时候很方便,只要传递域名字符串,就会返回域名对应的 IP 地址。只是返回时,地址信息装入 hostent 结构体。此结构体定义如下。

  1. struct hostent {
  2. char *h_name; // official name
  3. char **h_ailases; // alias list
  4. int h_addrtype; // host address type
  5. int h_length; // address length
  6. char **h_addr_list; // address list
  7. }

可以看到,通过调用 gethostbyname 函数返回的 hostent 结构体指针,其内容里不光有 IP 信息,还有其他信息。下面简要说明上述结构体各个成员。

  • h_name:该变量中有官方域名,官方域名代表某一主页,但实际上,一些著名公司的域名并未用官方域名注册。
  • h_aliases:可以通过多个域名访问同一主页。同一 IP 可以绑定多个域名,因此,除官方域名外还可指定其他域名。这些信息可以通过 h_aliases 获得。
  • h_addrtypegethostbyname 函数不仅支持 IPv4,还支持 IPv6。因此,可以通过此变量获取保存在 h_addr_list 的 IP 地址的地址族信息。若是 IPv4,则此变量存有 AF_INET。
  • h_length:保存 IP 地址长度。若是 IPv4 地址,因为是 4 个字节,则保存 4; IPv6时,因为是 16 个字节,故保存 16.
  • h_addr_list:这时最重要的成员。通过此变量以整数形式保存域名对应的 IP 地址。另外,用户较多的网站有可能分配多个 IP 给同一域名,利用多个服务器进行负载均衡。此时,同样可以通过此变量来获取 IP 地址信息。

下面是通过例子演示 gethostbyname 函数的应用,基于 Linux 平台。

  1. // gethostbyname.c 基于 Linux 平台
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <arpa/inet.h>
  7. #include <netdb.h>
  8. void error_handling(char *message);
  9. int main(int argc, char *argv[]) {
  10. // 1.检查输入
  11. if (argc!=2) {
  12. printf("Usage: %s <IP>\n", argv[0]);
  13. exit(1);
  14. }
  15. struct sockaddr_in addr;
  16. struct hostent *host;
  17. memset(&addr, 0, sizeof(addr));
  18. addr.sin_addr.s_addr = inet_addr(argv[1]);
  19. host = gethostbyaddr( (char*)&addr.sin_addr, 4, AF_INET);
  20. if (!host)
  21. error_handling("gethost ... error");
  22. int i;
  23. printf("Official name: %s \n", host->h_name);
  24. for (i=0; host->h_aliases[i]; i++)
  25. printf("Aliases %d: %s \n", i+1, host->h_aliases[i]);
  26. printf("Address type: %s \n", (host->h_addrtype==AF_INET) ? "AF_INET" : "AF_INET6");
  27. for (i=0; host->h_addr_list[i]; i++)
  28. printf("IP addr %d: %s \n", i+1, inet_ntoa(*(struct in_addr*) host->h_addr_list[i]));
  29. return 0;
  30. }
  31. void error_handling(char *message) {
  32. fputs(message, stderr);
  33. fputc('\n', stderr);
  34. exit(1);
  35. }

编译运行,这里我获取的是我的域名 hamsercoder.top 对应的 IP 地址:

§ 域名--IP 访问 - 图1

gethostbyaddr 利用 IP 地址获取域名

在直到了 IP 地址的情况,可以利用 gethostbyaddr 获取域名相关信息。

  1. struct hostent* gethostbyaddr(const char *addr, socklen_t len, int family);
  2. // 成功时返回 hostent 结构体变量地址值,失败时返回 NULL 指针
  3. // 参数:
  4. // -addr:含有 IP 地址信息的 in_addr 结构体指针,为了同时传递 IPv4 地址之外的其他信息,该
  5. // 变量的类型声明为 char 指针。
  6. // -len: 向第一个参数传递的地址信息,IPv4 时为 4,IPv6 时为 16.
  7. // -family:传递地址族信息,IPv4 时为 AF_INET,IPv6 时为 AF_INET6

下面通过示例演示该函数的使用方法,平台实现为 Linux。

  1. // gethostbyaddr.c 基于 Linux 平台
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <arpa/inet.h>
  7. #include <netdb.h>
  8. void error_handling(char *message);
  9. int main(int argc, char *argv[]) {
  10. // 1.检查输入
  11. if (argc!=2) {
  12. printf("Usage: %s <IP>\n", argv[0]);
  13. exit(1);
  14. }
  15. struct sockaddr_in addr;
  16. struct hostent *host;
  17. memset(&addr, 0, sizeof(addr));
  18. addr.sin_addr.s_addr = inet_addr(argv[1]);
  19. host = gethostbyaddr( (char*)&addr.sin_addr, 4, AF_INET);
  20. if (!host)
  21. error_handling("gethost ... error");
  22. int i;
  23. printf("Official name: %s \n", host->h_name);
  24. for (i=0; host->h_aliases[i]; i++)
  25. printf("Aliases %d: %s \n", i+1, host->h_aliases[i]);
  26. printf("Address type: %s \n", (host->h_addrtype==AF_INET) ? "AF_INET" : "AF_INET6");
  27. for (i=0; host->h_addr_list[i]; i++)
  28. printf("IP addr %d: %s \n", i+1, inet_ntoa(*(struct in_addr*) host->h_addr_list[i]));
  29. return 0;
  30. }
  31. void error_handling(char *message) {
  32. fputs(message, stderr);
  33. fputc('\n', stderr);
  34. exit(1);
  35. }

通过 ping 得到 www.google.com 的一个主机,然后运行程序

§ 域名--IP 访问 - 图2

Windows 平台下的实现

gethostbyname 实现

  1. // gethostbyname_win.c 基于 Windows 平台
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <winsock2.h>
  5. void ErrorHandling(char *message);
  6. int main(int argc, char *argv[]) {
  7. // 1.检查输入
  8. if (argc!=2) {
  9. printf("Usage: %s <IP>\n", argv[0]);
  10. exit(1);
  11. }
  12. WSADATA wsaData;
  13. if ( WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
  14. ErrorHandling("WSAStartup() error");
  15. // 2.通过域名获取地址
  16. struct hostent *host;
  17. host = gethostbyname( (argv[1]) );
  18. if (!host)
  19. ErrorHandling("gethost... error");
  20. int i;
  21. printf("Official name: %s \n", host->h_name);
  22. for (i=0; host->h_aliases[i]; i++)
  23. printf("Aliases %d: %s \n", i+1, host->h_aliases[i]);
  24. printf("Address type: %s \n", (host->h_addrtype==AF_INET) ? "AF_INET" : "AF_INET6");
  25. for (i=0; host->h_addr_list[i]; i++)
  26. printf("IP addr %d: %s \n", i+1, inet_ntoa(*(struct in_addr*) host->h_addr_list[i]));
  27. WSACleanup();
  28. return 0;
  29. }
  30. void ErrorHandling(char *message) {
  31. fputs(message, stderr);
  32. fputc('\n', stderr);
  33. exit(1);
  34. }

结果如下,可以看到和 Linux 的结果差了一些,这个是因为 hamstercoder.top 就是部署在 Linux 下的,所以结果上会有差异。

§ 域名--IP 访问 - 图3

gethostbyaddr 实现

和 Linux 下的类似,函数如下

  1. // gethostbyaddr_win.c 基于 Windows 平台
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <winsock2.h>
  5. void ErrorHandling(char *message);
  6. int main(int argc, char *argv[]) {
  7. // 1.检查输入
  8. if (argc!=2) {
  9. printf("Usage: %s <IP>\n", argv[0]);
  10. exit(1);
  11. }
  12. WSADATA wsaData;
  13. if ( WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
  14. ErrorHandling("WSAStartup() error");
  15. // 2.通过域名获取地址
  16. struct hostent *host;
  17. SOCKADDR_IN addr;
  18. memset(&addr, 0, sizeof(addr));
  19. addr.sin_addr.s_addr = inet_addr(argv[1]);
  20. host = gethostbyaddr( (char*)&addr.sin_addr, 4, AF_INET );
  21. if (!host)
  22. ErrorHandling("gethost... error");
  23. int i;
  24. printf("Official name: %s \n", host->h_name);
  25. for (i=0; host->h_aliases[i]; i++)
  26. printf("Aliases %d: %s \n", i+1, host->h_aliases[i]);
  27. printf("Address type: %s \n", (host->h_addrtype==AF_INET) ? "AF_INET" : "AF_INET6");
  28. for (i=0; host->h_addr_list[i]; i++)
  29. printf("IP addr %d: %s \n", i+1, inet_ntoa(*(struct in_addr*) host->h_addr_list[i]));
  30. WSACleanup();
  31. return 0;
  32. }
  33. void ErrorHandling(char *message) {
  34. fputs(message, stderr);
  35. fputc('\n', stderr);
  36. exit(1);
  37. }

这里同样查看 199.59.148.201 的域名,结果和 Linux 下的一样。

§ 域名--IP 访问 - 图4