【问题标题】:Got local host name, working on windows, but not in Linux有本地主机名,在 Windows 上工作,但在 Linux 上不行
【发布时间】:2013-12-02 16:43:15
【问题描述】:

我写了一个程序来获取本地主机名。如果不是很明显,我的意思是获取本地机器的主机名类似于gethostname的方法,而不是获取字符串localhost

我使用getaddrinfoNULL 作为主机名,然后使用第一个地址调用getnameinfo

它在 Windows 机器上完美运行,并给了我规范的主机名,但在 Linux 中它没有给我本地主机名,给我:: 用于 IPv6 或0.0.0.0 用于 IPv4。

请注意,我在getaddrinfo 中使用了AI_PASSIVE 标志,这意味着它给我的地址不超过两个。

如果我在getnameinfo 中使用NI_NAMEREQD,它会失败。

我这样做是因为我有一个服务器,有时我想监听所有接口,有时我想监听一个特定的接口,我已经有了addrinfo,如果可能的话我只想从中获取主机名.

如何让它在 Linux 上运行? 我错过了什么吗?

感谢您的帮助。

这是我的代码:(跨平台、Windows 和 Linux,只需复制并过去) 您可以在两者上编译和运行,看看区别。

#include <iostream> 

#ifdef WIN32

#ifdef UNICODE
#undef UNICODE /* don't want Unicode, to keep code compatibility */
#endif

#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
class CWSAInitializer{
public:
    CWSAInitializer(){
        WSADATA data;
        WSAStartup(MAKEWORD(2,2),&data);
    }
    ~CWSAInitializer(){
        WSACleanup();
    }
}autoInit;

#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#endif

const char* get_hostname(struct addrinfo* info, char buff[], int buff_len)
{
    int addrlen = (int)info->ai_addrlen;
    int res = getnameinfo(info->ai_addr, addrlen, buff, buff_len, NULL, 0, 0);
    if(res){
        return NULL;
    }
    return buff;
}

int main () 
{
    char temp[100];
    addrinfo *ai,hints;
    memset(&hints,0,sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_NUMERICSERV;
    hints.ai_flags |= AI_PASSIVE;

    int res = getaddrinfo(NULL, "0", &hints, &ai); 
    if(res){
        std::cerr<<gai_strerror(res)<<std::endl;
        return -1;
    }
    std::cout<< get_hostname(ai,temp,100)<<std::endl;
    freeaddrinfo(ai);

    return 0;
}

编辑

  1. 服务器也应该接受来自其他机器的客户端,所以它不能报告监听::0.0.0.0

  2. 我知道我可以这样修补它:

if(std::string("::") == hostname || std::string("0.0.0.0") == hostname) gethostname(hostname,100)

  1. 我不想得到localhost 作为结果,除非地址是127.0.0.1::1

【问题讨论】:

  • 如果您只想要本地主机名,为什么不使用 INADDR_LOOPBACK?
  • 我不想要 localhost 界面。服务器正在外面监听,我想知道我当前正在监听哪个主机名。如果客户端尝试连接到 :: 或 0.0.0.0,它将无法连接。

标签: c++ c linux windows getaddrinfo


【解决方案1】:

getaddrinfo() 返回struct addrinfo 节点列表的头部。

使用struct addrinfo 的成员ai_next 遍历此列表,以查找机器所有接口的地址。

要接收除通配符地址之外的任何其他内容,请不要在传递的提示中指定 AI_PASSIVE 标志。


更新赋予机器的各种名称和/或其接口地址:

  1. gethostname() 返回的主机名 ("hostname") 是主机的属性。它在主机上配置,不保存在任何外部数据库中。此主机名每个定义都没有链接到可能的接口地址解析到的任何名称。然而,主机名可能配置以匹配一个地址(机器接口的)解析到的名称。 p>

  2. 一台机器可能提供多个接口。这些接口中的每一个地址都应该解析为不同的名称,而这又可能与gethostname() 返回的名称不同(参见上面的 1.)。这适用于所有类型的接口,包括 IPv4 和 IPv6。还有虚拟通配符地址(0.0.0.0for IPv4),它允许程序绑定和侦听机器提供的 all 接口(此处输入 IPv4)。通配符地址有没有名称。

1. 和 2. 的结论是:没有名称...类似于 [returned by] gethostname() 但规范。”! p>

【讨论】:

  • 在 Windows 和 Linux 上,我在列表中有两个地址:一个给我 :: 另一个 0.0.0.0 我故意使用了 AI_PASSIVE。我不想得到localhost 我想得到规范的主机名。
  • 所以,如果我理解正确,如果我希望它在 Linux 上工作,如果我正在监听任何接口(将 NULL 给第一个 getaddrinfo 参数),我需要使用 gethostname ,或使用另一个没有AI_PASSIVE 标志的getaddrinfo。也许真的没有别的办法了。
  • 不好,它给了我localhost作为名字。我想要 THE 机器名。像 gethostname 但规范。
  • 那不存在,是吗?每个地址都有自己的名字,一台机器可以有很多网卡和很多地址。
猜你喜欢
  • 2018-10-27
  • 1970-01-01
  • 1970-01-01
  • 2021-02-18
  • 1970-01-01
  • 2020-11-03
  • 1970-01-01
  • 2018-08-01
  • 1970-01-01
相关资源
最近更新 更多