简体   繁体   中英

how to connect to a local host using winsock2

I wrote this program to communicate internally with a server listening on port 27015. But the return value from the connect() give me error 10047. There was no problem with socket creating and getaddrinfo() return wasn't an error. I don't know why the socket won't connect, could it be a problem with the concert of network-byte and 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;
}

Use getaddrinfo instead.

Quoting Microsoft's documentation for inet_addr function

The inet_addr function converts a string containing an IPv4 dotted-decimal address into a proper address for the IN_ADDR structure.

Emphasis mine. No dotted decimal address, no address.

Also worth noting from the documentation page's section on the return value,

If the string in the cp parameter does not contain a legitimate Internet address, for example if a portion of an "abcd" address exceeds 255, then inet_addr returns the value INADDR_NONE .

Always check the return value to make sure it's not giving an error message.

Error 10047 is WSAEAFNOSUPPORT , which happens when you try to give connect() an IP address whose family is not supported by the socket that is being connected, ie by passing an AF_INET address to an AF_INET6 socket, or an AF_INET6 address to an AF_INET socket. In this case, the latter is happening.

And the reason this is happening is because your call to memset(&hints, 0, sizeof(hints)); is in the wrong place!

You declare the hints variable and don't zero it out initially, then you start to fill it in for an AF_INET socket, but then you zero it out with memset() just before you give it to getaddrinfo() . So getaddrinfo() sees the hints.ai_family value is 0 ( AF_UNSPEC ) thus giving permission for getaddrinfo() to return EITHER/BOTH an IPv4 OR/AND an IPv6 address for "localhost" . Most likely, getaddrinfo() is outputting an AF_INET6 address at the front of the output list (remember, getaddrinfo() outputs a null-terminated linked list of resolved IP addresses).

Then you proceed to create a new socket using a hard-coded AF_INET as the socket family, instead of using the value from result->ai_family , and then you give result->ai_addr to connect() , which fails with error 10047 if that IP address is an AF_INET6 address and not an AF_INET address.

With that said, try something more like this:

#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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM