Winsock未将主机名转换为IP地址

4

getaddrinfo()不会将主机名翻译为IP地址,因此不会connect()到服务器。我的实现有问题吗?编译时没有警告信息?

这个对connect的函数调用是否正确?

connect(client, result->ai_addr, result->ai_addrlen)

完整实现如下:

#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdio.h>
#include <iostream>

#pragma comment(lib, "Ws2_32.lib")

using namespace std;

int main (
          int argc,
          char* argv[])
{
if (argc != 3)
{
    cerr << "Usage: " << argv[0] << " [hostname] [port number]\n";
    exit(EXIT_FAILURE);
}

WSADATA wsaData;
WORD wVersionRequested;
int wError;

wVersionRequested = MAKEWORD(2, 2);

wError = WSAStartup(wVersionRequested, &wsaData);

if (wError != 0)
{
    cerr << "WSAStartup failed with error: " << wError << endl;
    exit (EXIT_FAILURE);
}

/*
* Confirm that the WinSock DLL supports 2.2.
* Note that if the DLL supports versions greater
* than 2.2 in addition to 2.2, it will still return 
* 2.2 in wVersion since that is the version we 
* requested. 
*/

if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
    cerr << "Could not find a usable version of Winsock.dll." << endl;
    WSACleanup();
    exit(EXIT_FAILURE);
} else {
    cout << "The Winsock 2.2 dll was found." << endl;
}

SOCKET client;

if ((client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR)
{
    cerr << "Error: socket() return value == SOCKET_ERROR" << endl;
    WSACleanup();
    exit (EXIT_FAILURE);
}

cout << "Created a socket." << endl;

struct addrinfo *result = NULL;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

if ((wError = getaddrinfo(
                    argv[1],
                    argv[2],
                    &hints,
                    &result)) !=0 )
{
    freeaddrinfo(result);
    WSACleanup();
    if (wError == 11001)
    {
        cerr << "Error: occurred: getaddrinfo() failed "
             << wError << " - Host not found." << endl;
        exit(EXIT_FAILURE);
    }

    cerr << "Error: occurred: getaddrinfo() failed "
            << wError << endl;
    exit(EXIT_FAILURE);
}
/*
* Attempt to connect to the Server
*
*/

switch (wError = connect(client, result->ai_addr, result->ai_addrlen)) {
    case 0:
        cerr << "Resolved hostname." << endl;
        break;
    case SOCKET_ERROR:
        wError = WSAGetLastError();
        cerr << "Error: connet() failed "
                "Details: " << wError << endl;
        closesocket(client);
        freeaddrinfo(result);
        WSACleanup();
        exit(EXIT_FAILURE);
        break;
    default:
        cerr << "Fatal connect() error: unexpected "
                "return value." << endl;
        closesocket(client);
        freeaddrinfo(result);
        WSACleanup();
        exit(EXIT_FAILURE);
        break;
}

cout << "Connected to server." << endl;

closesocket(client);
freeaddrinfo(result);
WSACleanup();
exit(EXIT_SUCCESS);
}

你是怎么运行它的?我直接复制了你的代码并构建了它,然后运行了“testresolve stackoverflow.com 80”,它正确解析了主机并建立了连接。 - Graeme Perrow
有趣的是:服务器将在指定端口上运行在一台独立的机器上。在命令行中,“hostname”返回SAMPLE。使用上述实现:SAMPLE 1234 - 错误:connet()失败。详情:10061。 - Aaron
10061 = WSAECONNREFUSED,这意味着主机名已被解析,但在该端口号上没有任何监听。 - Graeme Perrow
谢谢!然而,从服务器端来看:状态侦听在X端口上 - 例如它工作:如果服务器正在侦听1234端口 - 客户端:127.0.0.1 1234 - 这很好运行,但不是:SAMPLE 1234 - 奇怪? - Aaron
你确定指定的端口已经开放,可以从外部进行访问吗? - arul
检查你的防火墙设置。 - arul
2个回答

4
getaddrinfo可能会提供给你一个IPv6地址,或者机器有多个IP地址,并且你正在尝试连接错误的IP地址。此外,如果你的服务器正在监听127.0.0.1并且你试图连接到真实的IP地址,连接将失败。同样,如果服务器正在侦听真实的IP地址,并且你尝试使用127.0.0.1进行连接,连接也将失败。如果服务器在0.0.0.0上侦听,则两个地址都应该工作。要侦听0.0.0.0,你需要编写类似于下面的代码:
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port=htons( port_num );
bind( s, (sockaddr *)&sin, sizeof( sin ) );

如何将服务器设置为监听0.0.0.0? - Aaron
这是我在Windows上的第一个Socket实现 :( 我还有很多要学习 :) - Aaron
在调用listen之前,您需要将要监听的地址传递给bind()函数。您可以使用INADDR_ANY作为一种快捷方式。 - Graeme Perrow
已更新答案以包含此内容。 - Graeme Perrow

1
尝试将 hint.ai_family 设置为 AF_UNSPEC 而非 AF_INET,我相信当指定 AF_INET 时,getaddrinfo 函数会接受类似 IPv4 的地址。

如果主机名为“SAMPLE”,如果作为参数传递-不起作用,但作为IP地址(在本地计算机上)它可以工作:例如127.0.0.1。 - Aaron
你确定提供的主机名是有效的吗? - arul
从cmd命令行中:hostname返回SAMPLE,因此:在运行服务器的地方,SAMPLE 1234返回错误:connet()失败,详情:10061。 - Aaron
好的,您提供的端口正确吗?10061错误意味着“连接被拒绝”,通常是选择了错误的端口的迹象。 - arul
是的,确认为TCP,本地端口1234,本地地址127.0.0.1 - 但不确定为什么:127.0.0.1 1234 - 可以工作,但不行的是:SAMPLE 127.0.0.1 - 因为SAMPLE是主机名? - Aaron
可能是打错了,但是:使用样例 127.0.0.1 应用程序正在尝试连接到一个无效的端口上的样例主机。 - arul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接