【问题标题】:How do I get the host name of a server?如何获取服务器的主机名?
【发布时间】:2016-03-24 10:10:59
【问题描述】:

我在 C++ 中创建了一个服务器和客户端,我希望它们在同一网络上但在不同机器上运行时相互连接。我目前正在使用以下代码让服务器连接到网络:

#define HOST_PORT "27015"

WSADATA wsaData;
int status;
struct addrinfo * data;
struct addrinfo hints;

WSAStartup(MAKEWORD(2, 2), &wsaData);

ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_IP;
hints.ai_flags = AI_PASSIVE;

char hostname[1024];
hostname[1023] = '\0';
gethostname(hostname, 1023);

if (getaddrinfo(hostname, HOST_PORT, &hints, &data))
{
    std::cout << "Unable to translate host name to address\n";
    WSACleanup();

    return 1;
}

客户端尝试使用类似代码进行连接:

#define DEFAULT_PORT "27015"

struct addrinfo hints;

ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

char hostname[1024];
hostname[1023] = '\0';
gethostname(hostname, 1023);

struct addrinfo *result = NULL;
int iResult = getaddrinfo(hostname, DEFAULT_PORT, &hints, &result);

if (iResult != 0)
{
    std::cout << ("getaddrinfo failed with error: %d\n", iResult);
    WSACleanup();

    return false;
}

当客户端和服务器在同一台机器上时,这可以正常工作,但是当它们在不同的机器上时如何允许它们连接?我希望我在使用gettaddrinfo()时需要客户端连接到相同的主机名,但是如何获取服务器的主机名? (例如,如果服务器上的hostname变成了“InsertNameHere”,如何让客户端检测到“InsertNameHere”并将其作为getaddrinfo()中的第一个参数?)

【问题讨论】:

  • 客户端必须知道服务器的主机名或IP。
  • @CristiFati 那么如何让客户端和服务器在不同的机器上连接?
  • 服务器正常。对于客户端,而不是调用gethostname,您应该指定它(或者如果您愿意,可以从配置中读取它)。

标签: c++ sockets server client host


【解决方案1】:

您的问题相当普遍,有几种解决方法。

手动配置

例如,您的服务器可能会发现它的 IP4 地址,将其打印到控制台,然后您以某种方式在客户端应用程序中手动指定该地址,例如作为命令行参数,或在某些配置文件中。

这是对开发人员最友好,但对用户最不友好的方式。

服务发布

您的服务器可能会在启动时将自己注册到客户端可以读取的某个位置。人们通常在企业 Windows 环境中实现此方法,其中 Active Directory 是“某个地方”。如果您遇到这种情况,请see this article 获取您需要的 WinSock API。

服务发现

或者,您可以自己实现发现机制,例如使用 UDP 广播。

在您的服务器中,侦听某个 UDP 端口,等待某个发现数据报,并以一些“发现的 OK”数据报进行响应。

在您的客户端中,在启动时,将发现 UDP 数据报发送到该 UDP 端口号的广播地址。如果您的服务器 [s] 在客户端所在的同一子网上运行,则客户端将收到“发现的 OK”消息 [s]。如果只有一个响应,您就知道只有一个可访问的服务器,您可以立即连接。如果有多个响应,则可能意味着有多个服务器,您可以询问用户在哪里连接。

这种方法相对难以正确实施(例如,UDP 不提供保证交付,因此需要重试和超时),但它是最用户友好的方式。如果您曾经玩过 Quake 之类的老式 LAN 游戏,那么他们就是通过这种方式发现自己的服务器的。

我想补充一下您可以使用的第三方库,例如 CollageReplicaNet,但是我没有这些方面的实践经验,不能推荐任何其中。

【讨论】:

  • 那时我可能会选择第一个选项,但我将如何实现呢?服务器将在多台机器上使用。在我用来制作服务器的当前机器上,IP4 地址可能是X,但是一旦它工作,我会将它放在另一台机器上,它的地址可能是Y。怎样才能随时获取到服务器所在机器的具体地址,然后传给客户端,这样客户端就可以连接到服务器了?
  • 能不能让客户端直接在网络上搜索服务器的名字(它的可执行文件名是“MusicServer.exe”),找到后连接?如果是这样,我该怎么做?我还会在服务器和客户端中使用getaddrinfo(),以便它们可以相互连接吗?
  • 不,MusicServer.exe 是您 PC 上的进程名称。进程名称不会暴露给网络。如果是 IP,您当然可以使用名称代替,但不是进程的名称,而是服务器计算机的网络名称。要找出计算机的名称,请运行命令提示符(Windows+R、cmd、回车),然后在命令提示符中输入主机名并按回车键。
  • 在您的代码中,您调用了获取本地计算机名称的 gethostname。您需要删除此调用,而不是使用“主机名”缓冲区使用命令行参数或配置参数,它将接收服务器的主机名。然后继续 getaddrinfo()。顺便说一句,为了测试和调试,当服务器和客户端在同一台 PC 上时,您可以使用一个名为“localhost”的特殊主机名,它将始终将您连接到本地 PC。
  • 好吧,我认为您可能应该根据您的平台从以下示例开始:msdn.microsoft.com/en-us/library/windows/desktop/… – Windows linuxhowtos.org/C_C++/socket.htm – Linux 它们都实现了大致相同的,一个非常简单的 TCP 客户端和服务器。
【解决方案2】:

要连接到远程服务器,您需要获取它的 IP 地址或主机名。默认方法是手动将其作为参数传递或使用 ZooKeeper 等命名服务(请参阅wiki

最简单和最好的方法是配置您的网络并使用 DNS 而不是直接 IP(例如 myserver1.mycompany.com:27015,其中 27015 是 TCP 端口)。

【讨论】:

  • 服务器可执行文件的名称是“MusicServer.exe”,那我在客户端使用getaddrinfo(MusicServer:27015, DEFAULT_PORT, &amp;hints, &amp;result)好吗?
  • IP 地址/主机名与“可执行文件名”无关。这就是网络的工作方式。当您在浏览器中输入“www.google.com”时,您所做的完全一样。您正在手动提供服务器地址。客户端无法知道“自动”连接的位置。您必须手动为您的客户端提供 IP/主机名。通过命令行参数,例如:myapp.exe server.address.here 或者你可以使用一些“发现服务”,但我认为这不是你的情况。
猜你喜欢
  • 2014-08-09
  • 1970-01-01
  • 1970-01-01
  • 2011-05-04
  • 2016-10-30
  • 2014-07-28
  • 1970-01-01
  • 1970-01-01
  • 2011-01-09
相关资源
最近更新 更多