c++ - 尝试使用winsock连接时出现错误10061

标签 c++ winsock

我有一个客户端和服务器在同一台计算机上运行。 客户端通过 80 端口连接到 127.0.0.1。服务器同时监听 80 端口。

当我启动客户端并尝试连接时,它会抛出错误 10061(被目标计算机主动拒绝)。我尝试关闭本地防火墙,但这并没有改变任何东西。 我绝对坚持这个。这是连接到服务器的代码:

void Base::Connect(string ip, string port)
{
    int status;
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo hints;
    struct addrinfo *servinfo;  // will point to the results

    memset(&hints, 0, sizeof hints); // make sure the struct is empty
    hints.ai_family = AF_UNSPEC;     // don't care IPv4 or IPv6
    hints.ai_socktype = SOCK_STREAM; // TCP stream sockets

    // get ready to connect
    status = getaddrinfo(ip.c_str(), port.c_str(), &hints, &servinfo);

    // Socket Setup
    if ((ConnectSocket = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == INVALID_SOCKET)
    {
        printf("[NETWORKING] An error occured when setting up socket\n");
    }

    // Connect
    WSACleanup();
    if (connect(ConnectSocket, servinfo->ai_addr, (int)servinfo->ai_addrlen) == SOCKET_ERROR)
    {
        int error = WSAGetLastError();
        printf("Connect error: ", error);
    }
}

这是来自服务器的用于监听传入连接的代码:

int _tmain(int argc, _TCHAR* argv[])
{
// WINDOWS SETUP
WSAData wsaData;
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) 
{
    fprintf(stderr, "WSAStartup failed.\n");
    exit(1);
}

// PREPARE TO LAUNCH
int status;
struct sockaddr_storage their_addr;
socklen_t addr_size;
int sockfd, new_fd = 0;

struct addrinfo hints;
struct addrinfo *servinfo;  // will point to the results

memset(&hints, 0, sizeof hints); // make sure the struct is empty
hints.ai_family = AF_UNSPEC;     // don't care IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
hints.ai_flags = AI_PASSIVE;     // fill in my IP for me

if ((status = getaddrinfo(NULL, "80", &hints, &servinfo)) != 0) 
{
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
    getchar();
    exit(1);
}

// GET THE FILE DESCRIPTOR  
SOCKET mSocket = INVALID_SOCKET;
mSocket = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);

// WHAT PORT AM I ON
bind(mSocket, servinfo->ai_addr, servinfo->ai_addrlen);

int backlog = 2;
listen(mSocket, backlog);

// SERVER STARTED LISTENING SUCCESFULLY
printf("Server is listenening...\n");

// ACCEPT
printf("Server starts accepting clients...\n");
addr_size = sizeof their_addr;
new_fd = accept(mSocket, (struct sockaddr*)&their_addr, &addr_size);

printf("Server ended");
getchar();

// lose the pesky "Address already in use" error message
char yes='1';

if (setsockopt(mSocket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
    perror("setsockopt");
    exit(1);
} 

return 0;
}

欢迎任何帮助!提前致谢

最佳答案

在客户端:

  1. 在调用connect()之前不要调用WSACleanup()
  2. 您没有对 getaddrinfo() 进行任何错误处理。
  3. 您没有设置 ai_flags 来匹配您的输入值(例如 AI_NUMERICHOST)。
  4. 您没有释放 getaddrinfo() 返回的内存。
  5. 您没有考虑到您正在为 getaddrinfo() 指定 AF_UNSPEC,因此它可能会返回多个地址。您应该尝试连接所有这些设备,直到其中一个成功为止。

试试这个:

void Base::Connect(string ip, string port)
{
    int status, error;
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo hints = {0};
    struct addrinfo *servinfo;  // will point to the results

    hints.ai_family = AF_UNSPEC;     // don't care IPv4 or IPv6
    hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
    hints.ai_flags = AI_NUMERICHOST; // parse an IP address
    //hints.ai_flags |= AI_NUMERICSERV; // parse a port number (not supported on Windows)

    // get ready to connect
    status = getaddrinfo(ip.c_str(), port.c_str(), &hints, &servinfo);
    if (status != 0)
    {
        printf("getaddrinfo error: (%d) %s\n", status, gai_strerror(status));
        return;
    }

    addrinfo *addr = servinfo;
    do
    {
        // Socket Setup
        ConnectSocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET)
        {
            printf("socket error: %d\n", WSAGetLastError());
        }
        else
        {
            // Connect
            if (connect(ConnectSocket, addr->ai_addr, addr->ai_addrlen) != SOCKET_ERROR)
            {
                printf("connected to server\n");
                break;
            }

            printf("connect error: %d\n", WSAGetLastError());

            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
        }

        addr = addr->ai_next;
    }
    while (addr != NULL);

    freeaddrinfo(servinfo);

    if (ConnectSocket == INVALID_SOCKET)
        printf("unable to connect to server\n");
}

在服务器端:

  1. 您没有对 socket()bind()listen() 进行任何错误处理。
  2. SO_REUSEADDR 必须在调用 bind() 之前启用,而不是之后。而且您甚至也没有正确启用它。
  3. 您没有释放 getaddrinfo() 返回的内存。

试试这个:

int _tmain(int argc, _TCHAR* argv[])
{
    // WINDOWS SETUP
    WSAData wsaData;
    if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) 
    {
        fprintf(stderr, "WSAStartup failed.\n");
        exit(1);
    }

    // PREPARE TO LAUNCH
    int status;
    struct sockaddr_storage their_addr;
    socklen_t addr_size;
    SOCKET client;

    struct addrinfo hints = {0};
    struct addrinfo *servinfo;  // will point to the results

    hints.ai_family = AF_UNSPEC;     // don't care IPv4 or IPv6
    hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
    hints.ai_flags = AI_PASSIVE;     // fill in my IP for me
    //hints.ai_flags |= AI_NUMERICSERV; // parse a port number (not supported on Windows)

    status = getaddrinfo(NULL, "80", &hints, &servinfo);
    if (status != 0) 
    {
        fprintf(stderr, "getaddrinfo error: (%d) %s\n", status, gai_strerror(status));
        getchar();
        exit(1);
    }

    // optional, loop through servinfo creating a separate
    // listening socket for each address reported...

    // GET THE FILE DESCRIPTOR  
    SOCKET mSocket = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
    if (mSocket == INVALID_SOCKET)
    {
        fprintf(stderr, "socket error: %d\n", WSAGetLastError());
        freeaddrinfo(servinfo);
        closesocket(mSocket);
        getchar();
        exit(1);
    }

    // lose the pesky "Address already in use" error message
    BOOL yes = TRUE;
    if (setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes)) == SOCKET_ERROR)
    {
        fprintf(stderr, "setsockopt error: %d\n", WSAGetLastError());
        freeaddrinfo(servinfo);
        closesocket(mSocket);
        getchar();
        exit(1);
    }

    // WHAT PORT AM I ON
    if (bind(mSocket, servinfo->ai_addr, servinfo->ai_addrlen) == SOCKET_ERROR)
    {
        fprintf(stderr, "bind error: %d\n", WSAGetLastError());
        freeaddrinfo(servinfo);
        closesocket(mSocket);
        getchar();
        exit(1);
    }

    freeaddrinfo(servinfo);

    int backlog = 2;
    if (listen(mSocket, backlog) == SOCKET_ERROR)
    {
        fprintf(stderr, "listen error: %d\n", WSAGetLastError());
        closesocket(mSocket);
        getchar();
        exit(1);
    }

    // SERVER STARTED LISTENING SUCCESFULLY
    printf("Server is listening...\n");

    // ACCEPT
    addr_size = sizeof their_addr;
    client = accept(mSocket, (struct sockaddr*)&their_addr, &addr_size);
    if (client == INVALID_SOCKET)
    {
        fprintf(stderr, "accept error: %d\n", WSAGetLastError());
    }
    else
    {
        char ip[NI_MAXHOST] = {0};
        char port[NI_MAXSERV] = {0};

        status = getnameinfo((struct sockaddr*)&their_addr, addr_size, ip, NI_MAXHOST, port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
        if (status == 0)
            printf("Client connected from %s:%s\n", ip, port);
        else
            printf("Client connected. getnameinfo error: (%d) %s\n", status, gai_strerror(status));

        //...

        closesocket(client);
    }        

    closesocket(mSocket);
    printf("Server ended");

    getchar();

    return 0;
}

关于c++ - 尝试使用winsock连接时出现错误10061,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23071000/

相关文章:

winapi - WinSock getaddrinfo 从主机名获取 IP 失败,直到调用 ipconfig/flushdns

c++ - 未绘制 QToolButton 上的文本

c++ - 当服务器重新启动并且客户端收到 WSAECONNRESET 错误代码时,我是否应该重新创建整个套接字

c++ - 使用 TCP 从客户端向服务器发送字节的问题

c++ - 如何在 TCP/IP 中为消息长度添加前缀

c++ - 通过套接字发送和接收原始结构不安全吗?

c++ - C++ 模板实现文件的正确文件扩展名是什么?

c++ - 为什么 C++ 中实现类的语法是这样的?

c++ - 如何在 unordered_map 中设置值并确定是否添加了新键

C++ Win32 如何将此函数放在单独的 cpp 文件中?