客户端的 getaddrinfo() 出现问题

问题描述 投票:0回答:1

我正在展示服务器和客户端的代码。平台是Linux(Fedora)。我遇到的问题是,客户端在一段时间后在 connect() 调用上超时并失败。然而,更神秘的是 getaddrinfo() 的作用。它用于 connect() 的地址与我传递给结构提示的地址不同。为什么会这样?

为什么程序客户端无法连接?

Server.cpp

#include <sys/types.h>

#include <sys/socket.h>
#include <netdb.h>
#include<arpa/inet.h>

#include <sys/un.h>

#include<unistd.h>
#include<stdlib.h>

#include<iostream>
using namespace std;

int main(int argc, char *argv[]) {

    if (argc != 2) {
        cout << "Usage: " << argv[0] << " port-number" << endl;
        exit(1);
    }
    else cout << "Server(), incoming port: " << argv[1] << endl;

    int sockDescriptor, reqSocket, childpid;

    struct addrinfo hints, *result, *p;
    memset(&hints, 0, sizeof(hints));

    hints.ai_flags = AI_PASSIVE;
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    char buf[126];
    if (gethostname(buf, sizeof(buf)) < 0){
        cout << "Server(), gethostname() failed." << endl;
        exit(1);
    }
    else cout << "Server(), Hostname: " << buf << endl;

    if (getaddrinfo(buf, argv[1], &hints, &result) != 0) {
        cout << "Server(), getaddrinfo() failed" << endl;
        exit(1);
    }

    struct addrinfo sa, sa4;
    memset(&sa, 0, sizeof(sa));
    memset(&sa4, 0, sizeof(sa4));

    bool AllDone = false;

    for (p = result; p != NULL; p = p->ai_next) {
        if (p->ai_family == AF_INET6) {
            if (!AllDone) {
                memcpy(&sa, p, sizeof(sa));
                sockDescriptor = socket(sa.ai_family, sa.ai_socktype, sa.ai_protocol);
                if (sockDescriptor == -1) continue;
                if (bind(sockDescriptor, sa.ai_addr, sa.ai_addrlen) == -1) {
                    close(sockDescriptor);
                }
                else {
                    AllDone = true;
                    inet_ntop(sa.ai_family, &(sa.ai_addr), buf, 125);
                    cout << "Server(), Server Address: " << buf << endl;
                }
            } //endif AllDone
        }
        else if (p->ai_family == AF_INET) {
            memcpy(&sa4, p, sizeof(sa4));
            inet_ntop(sa4.ai_family, &(sa4.ai_addr), buf, 125);
            cout << "Server(), Server Address: " << buf << endl;
        }
    }

    freeaddrinfo(result);

    if (!AllDone) {
        cout << "Server(), getaddrinfo() did not get address..." << endl;
        exit(1);
    }
    else cout << "Server(), getaddrinfo() succeeded..." << endl;

    if (listen(sockDescriptor, 5) == -1) {
        cout << "Server(), listen() failed" << endl;
        close(sockDescriptor);
        exit(1);
    }

    for(;;) {
        if ((reqSocket = accept(sockDescriptor, NULL, NULL)) == -1) {
            cout << "Server(), accept() failed, continuing" << endl;
            continue;
        }

        if ((childpid = fork()) < 0) {
            cout << "Server(), Could not fork for accept. Quitting" << endl;
            close(sockDescriptor);
            exit(1);
        }
        else if (!childpid) {
            cout << "Server(), accepted client request..." << endl;
            close(reqSocket);
            exit(0);
        }
    }

    return 0;
}

Client.cpp

#include <sys/types.h>

#include <sys/socket.h>
#include <netdb.h>
#include<arpa/inet.h>

#include <sys/un.h>

#include<unistd.h>
#include<stdlib.h>

#include<iostream>
using namespace std;

int main(int argc, char *argv[]) {

    if (argc != 3) {
        cout << "Usage: " << argv[0] << " host-address"  << " port-number" << endl;
        exit(1);
    }
    else {
        cout << "Client(), incoming address: " << argv[1] << endl;
        cout << "Client(), incoming port: " << argv[2] << endl;
    }

    int sockDescriptor;
    struct addrinfo hints, *result, *p;
    memset(&hints, 0, sizeof(hints));

    hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
    hints.ai_family = AF_INET6;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    if (getaddrinfo(argv[1], argv[2], &hints, &result) != 0) {
        cout << "Client(), getaddrinfo() failed" << endl;
        exit(1);
    }

    struct addrinfo sa;
    memset(&sa, 0, sizeof(sa));

    bool AllDone = false;

    for (p = result; p != NULL; p = p->ai_next) {
        if (p->ai_family == AF_INET6) {
            if (!AllDone) {
                memcpy(&sa, p, sizeof(sa));
                sockDescriptor = socket(sa.ai_family, sa.ai_socktype, sa.ai_protocol);
                if (sockDescriptor == -1) continue;
                if (connect(sockDescriptor, sa.ai_addr, sa.ai_addrlen) == -1) {
                    close(sockDescriptor);
                    char buf[126];
                    inet_ntop(sa.ai_family, &(sa.ai_addr), buf, 125);
                    cout << "Client(), connect() failed for address: " << buf << endl;
                }
                else {
                    AllDone = true;
                    break;
                }
            } //endif AllDone
        }
    }

    freeaddrinfo(result);

    if (!AllDone) {
        cerr << "Client(), getaddrinfo() did not get address..." << endl;
        exit(1);
    }
    else {
        cout << "Client(), connection to server succeeded." << endl;
        close(sockDescriptor);
    }

    return 0;
}
c++ linux connection
1个回答
0
投票

问题最终解决如下。使用节点的主机名,不要使用 NULL。丢弃包含 0000 的地址。我将只显示针对服务器修改的主循环。

    struct addrinfo sa;
    memset(&sa, 0, sizeof(sa));

    bool AllDone = false;

    for (p = result; p != NULL; p = p->ai_next) {
        if (p->ai_family == AF_INET6) {
            struct sockaddr_in6 *psa = (struct sockaddr_in6*)p->ai_addr;
            inet_ntop(AF_INET6, &(psa->sin6_addr), buf, 125);

            if (strstr(buf, "::")) {
                cout << "Server(), Server ipv6 Address (skipped): " << buf << endl;
                continue;
            }

            if (!AllDone) {
                memcpy(&sa, p, sizeof(sa));
                sockDescriptor = socket(sa.ai_family, sa.ai_socktype, sa.ai_protocol);
                if (sockDescriptor == -1) continue;
                if (bind(sockDescriptor, sa.ai_addr, sa.ai_addrlen) == -1) {
                    close(sockDescriptor);
                }
                else {
                    AllDone = true;
                    cout << "Server(), bind() succeeded for address: " << buf << endl;
                }
            } //endif AllDone
        }
        else if (p->ai_family == AF_INET) {
            struct sockaddr_in *psa = (struct sockaddr_in*)p->ai_addr;
            inet_ntop(AF_INET, &(psa->sin_addr), buf, 125);
            cout << "Server(), Server ipv4  Address: " << buf << endl;
        }
    }

    freeaddrinfo(result);

© www.soinside.com 2019 - 2024. All rights reserved.