【问题标题】:how to connect to a local host using winsock2如何使用winsock2连接到本地主机
【发布时间】:2020-08-23 02:34:04
【问题描述】:

我编写这个程序是为了与侦听端口 27015 的服务器进行内部通信。但是来自 connect() 的返回值给了我错误 10047。创建套接字没有问题,getaddrinfo() 返回不是错误。不知道为什么socket连接不上,会不会是network-byte和host-byte一致的问题?

#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <Ws2tcpip.h>
#include <iphlpapi.h>
#define DEFAULT_PORT "27015"
using namespace std;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow) {
    WSADATA wsaData;
    // Initialize Winsock version 2.2
    int ret;
    // holds server info//
    if (ret = WSAStartup(MAKEWORD(2,2), &wsaData) != 0){
        std::cout << "WSAStartup failed with error %ld\n", WSAGetLastError());
        return 0;
    }
    else{
        cout << "The current status is:" << wsaData.szSystemStatus << "\n";
    }
      
    // Setup Winsock communication code here
    struct addrinfo *result = NULL, *ptr = NULL, hints;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
       
    memset(&hints, 0, sizeof(hints));
    int iResult = getaddrinfo("localhost", DEFAULT_PORT, &hints, &result);
    if (iResult != 0) {
        printf("getaddrinfo failed: %d\n", iResult);
        WSACleanup();
        return 1;
    }
    SOCKET Sending_socket; 
      
    Sending_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (Sending_socket == INVALID_SOCKET){
        cout << "socket error\n";
        WSACleanup();
        return 0;
    }
     
    // now we connect to the server ,RetCode=return of connect()
    int RetCode = connect(Sending_socket, result->ai_addr, (int)result->ai_addrlen);
    if (RetCode != 0) {
        int num_attempt = 0;
        while (RetCode != 0 && num_attempt != 100){
            printf("Error at socket(): %ld\n", WSAGetLastError());
            RetCode = connect(Sending_socket, result->ai_addr, (int)result->ai_addrlen);
            num_attempt++;
        }        
    }
    else {
        cout << "connect okay \n";
    }
    int them ;
    closesocket(Sending_socket);
    // When your application is finished call WSACleanup
    them = WSACleanup();
    // making sure to cleanup
    if (them != 0){
        cout << "WSACleanup failed with error " << WSAGetLastError();
        // and exit
        return 1;
    }
    return 1;
}

【问题讨论】:

  • inet_addr 无法解决任何问题。它将 IP 地址从字符串转换为二进制。 localhost 不是 IP 地址。
  • 要将主机名解析为 IP 地址,请使用 getaddrinfo()
  • 我使用 getaddrinfo() 来获取本地主机:` getaddrinfo("localhost",DEFAULT_PORT , &hints, &result)` 然后连接:connect(Sending_socket,result-&gt;ai_addr, (int)result-&gt;ai_addrlen); 但仍然错误占上风@Remy
  • @AsareAgyeiHarrison 那么你没有正确使用getaddrinfo()。 10049 是 WSAEADDRNOTAVAIL: "这也可能是由于连接 ...当远程地址或端口对远程计算机无效时(例如,地址或端口 0)。" 在调用connect() 之前,您是否正在检查getaddrinfo() 的返回值是否失败?调用 getaddrinfo() 时如何填充 hints?请edit您的问题显示您尝试过的新代码。
  • 错误现在是 10047 @Remy

标签: c++ winapi winsock2


【解决方案1】:

错误 10047 是 WSAEAFNOSUPPORT,当您尝试为 connect() 提供一个 IP 地址,其系列不受正在连接的套接字支持时,即通过将 AF_INET 地址传递给 AF_INET6 套接字时,会发生错误,或AF_INET6 地址到AF_INET 套接字。在这种情况下,后者正在发生。

发生这种情况的原因是因为您拨打 memset(&amp;hints, 0, sizeof(hints)); 的位置有误!

您声明了 hints 变量并且不要最初将其归零,然后您开始为AF_INET 套接字填充它,但随后您使用memset() 将其归零就在你把它交给getaddrinfo()之前。所以getaddrinfo() 看到hints.ai_family 的值为0 (AF_UNSPEC),因此允许getaddrinfo()"localhost" 返回一个IPv4 或/和一个IPv6 地址。最有可能的是,getaddrinfo() 在输出列表的前面输出了一个AF_INET6 地址(请记住,getaddrinfo() 输出一个以空结尾的链接列表解析的 IP 地址)。

然后您继续使用硬编码的AF_INET 作为套接字系列创建一个新套接字,而不是使用来自result-&gt;ai_family 的值,然后将result-&gt;ai_addr 分配给connect(),但失败并出现错误如果该 IP 地址是 AF_INET6 地址而不是 AF_INET 地址,则为 10047。

话虽如此,请尝试更多类似的东西:

#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <Ws2tcpip.h>
#include <iphlpapi.h>

#define DEFAULT_PORT "27015"

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    WSADATA wsaData;
    int ret;

    // Initialize Winsock version 2.2
    ret = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (ret != 0)
    {
        std::cout << "WSAStartup failed with error " << ret << "\n";
        return 0;
    }

    std::cout << "The current status is:" << wsaData.szSystemStatus << "\n";
      
    // Setup Winsock communication code here
    struct addrinfo *result = NULL, *ptr = NULL, hints;
    memset(&hints, 0, sizeof(hints)); // <-- MOVED HERE!!!
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
       
    ret = getaddrinfo("localhost", DEFAULT_PORT, &hints, &result);
    if (ret != 0)
    {
        std::cout << "getaddrinfo failed: " << ret << "\n";
        WSACleanup();
        return 0;
    }

    SOCKET Sending_socket = INVALID_SOCKET;

    for (int num_attempt = 0; num_attempt < 100; ++num_attempt)
    {
        Sending_socket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
        if (Sending_socket == INVALID_SOCKET)
        {
            std::cout << "socket failed: " << WSAGetLastError() << "\n";
            freeaddrinfo(result);
            WSACleanup();
            return 0;
        }

        // now we connect to the server
        ret = connect(Sending_socket, result->ai_addr, (int)result->ai_addrlen);
        if (ret == 0)
            break;

        std::cout << "Error at socket(): " << WSAGetLastError() << "\n";

        closesocket(Sending_socket);
        Sending_socket = INVALID_SOCKET;
    }

    /* alternatively:

    SOCKET Sending_socket = INVALID_SOCKET;

    for (int num_attempt = 0; Sending_socket == INVALID_SOCKET && num_attempt < 100; ++num_attempt)
    {
        for(ptr = result; ptr != NULL; ptr = ptr->ai_next)
        {
            Sending_socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
            if (Sending_socket == INVALID_SOCKET)
            {
                std::cout << "socket failed: " << WSAGetLastError() << "\n";
                freeaddrinfo(result);
                WSACleanup();
                return 0;
            }
     
            // now we connect to the server
            ret = connect(Sending_socket, ptr->ai_addr, (int)ptr->ai_addrlen);
            if (ret == 0)
                break;

            std::cout << "Error at socket(): " << WSAGetLastError() << "\n";

            closesocket(Sending_socket);
            Sending_socket = INVALID_SOCKET;
        }
    }
    */

    freeaddrinfo(result);

    if (Sending_socket != INVALID_SOCKET)
    {
        std::cout << "connect okay\n";

        // use Sending_socket as needed...

        closesocket(Sending_socket);
        ret = 1;
    }
    else
    {
        std::cout << "connect not okay\n";
        ret = 0;
    }

    // When your application is finished call WSACleanup
    WSACleanup();

    return ret;
}

【讨论】:

    【解决方案2】:

    Use getaddrinfo instead.

    引用微软的inet_addr function文档

    inet_addr 函数将包含IPv4 点分十进制地址 的字符串转换为IN_ADDR 结构的正确地址。

    强调我的。没有点分十进制地址,没有地址。

    还值得注意的是文档页面的返回值部分,

    如果 cp 参数中的字符串不包含合法的 Internet 地址,例如,如果“a.b.c.d”地址的一部分超过 255,则 inet_addr 返回值 INADDR_NONE

    始终检查返回值以确保它没有给出错误消息。

    【讨论】:

    • 对不起,我第一次没有真正费心提供解决方案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-24
    • 1970-01-01
    • 2020-09-04
    • 1970-01-01
    • 2021-07-27
    相关资源
    最近更新 更多