You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决connect()失败错误:Address family not supported by protocol family

问题与解决方案

问题详情

执行终端命令 ./client www.google.com 80 时触发错误:

connect() failed: Address family not supported by protocol family

怀疑问题出在getAddressInfo函数中,附上相关C语言代码:

#include <stdio.h> /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
#include <arpa/inet.h> /* for sockaddr_in and inet_addr() */
#include <stdlib.h> /* for atoi() and exit() */
#include <string.h> /* for memset() */
#include <unistd.h> /* for close() */
#include <netdb.h>
#include <sys/time.h>

#define RCVBUFSIZE 32 /* Size of receive buffer */

void DieWithError(char *errorMessage); /* Error handling function */

int getAddressInfo(const char* host, unsigned short* port) {
    struct addrinfo hints = {0};
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;

    struct addrinfo* result;
    int ret = getaddrinfo(host, "http", &hints, &result);
    if (ret != 0) {
        fprintf(stderr, "getaddrinfo() failed: %s\n", gai_strerror(ret));
        return -1;
    }

    struct sockaddr_in* sock_addr = (struct sockaddr_in*)result->ai_addr;
    char* servIP = inet_ntoa(sock_addr->sin_addr);

    *port = ntohs(sock_addr->sin_port);

    freeaddrinfo(result);

    return 0;
}

int main(int argc, char *argv[]) {
    int sock; /* Socket descriptor */
    struct sockaddr_in httpServAddr; /* HTTP server address */
    unsigned short httpServPort; /* HTTP server port */
    /* Server IP address (dotted quad) */
    char *httpRequest = "GET /index.html HTTP/1.1\r\n"
                        "Host: www.example.com\r\n"
                        "Connection: close\r\n\r\n"; /* HTTP request to send to the server */
    char httpBuffer[RCVBUFSIZE]; /* Buffer for HTTP response */
    int bytesRcvd, totalBytesRcvd; /* Bytes read in single recv() and total bytes read */

    if (argc < 2 || argc > 3) { /* Test for correct number of arguments */
        fprintf(stderr, "Usage: %s <Server IP> [<HTTP Port>]\n", argv[0]);
        exit(1);
    }

    const char* host = argv[1];

    if (getAddressInfo(host, &httpServPort) != 0) {
        DieWithError("Failed to get server address information");
    }

    if (argc == 3) {
        httpServPort = atoi(argv[2]); /* Use given port, if any */
    } else {
        httpServPort = 80; /* Default HTTP port */
    }

    /* Create a reliable, stream socket using TCP */
    if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
        DieWithError("socket() failed");
    }

    /* Construct the server address structure */
    memset(&httpServAddr, 0, sizeof(httpServAddr)); /* Zero out structure */
    httpServAddr.sin_family = AF_INET; /* Internet address family */
    httpServAddr.sin_addr.s_addr = inet_addr(host); /* Server IP address */
    httpServAddr.sin_port = htons(httpServPort); /* Server port */

    /* Establish the connection to the HTTP server */
    if (connect(sock, (struct sockaddr *) &httpServAddr, sizeof(httpServAddr)) < 0) {
        DieWithError("connect() failed");
    }

    /* Send the HTTP request to the server */
    if (send(sock, httpRequest, strlen(httpRequest), 0) != strlen(httpRequest)) {
        DieWithError("send() sent a different number of bytes than expected");
    }

    /* Receive the HTTP response from the server */
    totalBytesRcvd = 0;
    printf("Received: "); /* Setup to print the HTTP response */

    while ((bytesRcvd = recv(sock, httpBuffer, RCVBUFSIZE - 1, 0)) > 0) {
        totalBytesRcvd += bytesRcvd;
        httpBuffer[bytesRcvd] = '\0';
        printf("%s", httpBuffer);
    }

    if (bytesRcvd < 0) {
        DieWithError("recv() failed");
    }

    printf("\n"); /* Print a final linefeed */

    close(sock);
    exit(0);
}
/*
void calcRTT(char* host, char* servport, int trials) {

    struct addrinfo* servinfo = buildAddrInfo(url, port);
    int i;
    float sum = 0;
    for(i=0; i < trials; i++) {

        struct timeval start;
        struct timeval end;

    }


}

long timediff(struct timeval t1, struct timeval t2) {
    long elapsed = t2.tv_sec - t1.tv_sec;
    return elapsed * 1000;
}
 */


void DieWithError(char *errorMessage) {
    perror(errorMessage);
    exit(1);
}

同时希望实现终端输入URL的信息显示功能。


错误原因分析

  1. inet_addr无法解析域名:inet_addr(host)仅能处理点分十进制格式的IP地址,无法解析www.google.com这类域名,调用后会返回INADDR_NONE,导致sockaddr_in结构中的IP地址无效,最终触发connect错误。
  2. getAddressInfo功能被浪费:该函数调用getaddrinfo成功解析了域名和端口,但后续代码完全未使用解析出的IP地址,反而用inet_addr重新处理原域名,且后面的代码还覆盖了该函数获取到的端口值。

修复方案与功能实现

以下是修改后的代码,同时实现了URL解析信息显示功能:

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/time.h>

#define RCVBUFSIZE 1024  /* 增大接收缓冲区,避免截断响应 */

void DieWithError(char *errorMessage);

// 解析地址并返回addrinfo链表,同时打印解析信息
struct addrinfo* getAddressInfo(const char* host, const char* port_str) {
    struct addrinfo hints = {0};
    hints.ai_family = AF_UNSPEC;  // 同时支持IPv4和IPv6
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    struct addrinfo* result;
    int ret = getaddrinfo(host, port_str, &hints, &result);
    if (ret != 0) {
        fprintf(stderr, "getaddrinfo() failed: %s\n", gai_strerror(ret));
        return NULL;
    }

    // 打印解析到的地址信息
    printf("=== 解析URL信息 ===\n");
    printf("目标主机: %s\n", host);
    printf("目标端口: %s\n", port_str);
    
    struct addrinfo* ptr;
    char ip_str[INET6_ADDRSTRLEN];
    for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
        void* addr;
        char* ip_version;

        if (ptr->ai_family == AF_INET) {
            struct sockaddr_in* ipv4 = (struct sockaddr_in*)ptr->ai_addr;
            addr = &(ipv4->sin_addr);
            ip_version = "IPv4";
        } else {
            struct sockaddr_in6* ipv6 = (struct sockaddr_in6*)ptr->ai_addr;
            addr = &(ipv6->sin6_addr);
            ip_version = "IPv6";
        }

        inet_ntop(ptr->ai_family, addr, ip_str, sizeof(ip_str));
        printf("解析到%s地址: %s\n", ip_version, ip_str);
    }
    printf("===================\n\n");

    return result;
}

int main(int argc, char *argv[]) {
    int sock;
    struct addrinfo* servinfo;
    char *httpRequest;
    char httpBuffer[RCVBUFSIZE];
    int bytesRcvd, totalBytesRcvd;

    if (argc < 2 || argc > 3) {
        fprintf(stderr, "Usage: %s <Server Hostname/IP> [<HTTP Port>]\n", argv[0]);
        exit(1);
    }

    const char* host = argv[1];
    const char* port_str = (argc == 3) ? argv[2] : "80";

    // 解析地址并获取addrinfo
    servinfo = getAddressInfo(host, port_str);
    if (servinfo == NULL) {
        DieWithError("Failed to get server address information");
    }

    // 遍历addrinfo链表,尝试创建socket并连接
    struct addrinfo* ptr;
    for (ptr = servinfo; ptr != NULL; ptr = ptr->ai_next) {
        if ((sock = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol)) < 0) {
            perror("socket() failed");
            continue;
        }

        if (connect(sock, ptr->ai_addr, ptr->ai_addrlen) == 0) {
            break;  // 连接成功,跳出循环
        }

        close(sock);
        perror("connect() failed");
    }

    if (ptr == NULL) {
        fprintf(stderr, "Failed to connect to any address\n");
        freeaddrinfo(servinfo);
        exit(1);
    }

    // 动态生成HTTP请求,替换Host字段为输入的主机名
    char request_template[] = "GET /index.html HTTP/1.1\r\n"
                              "Host: %s\r\n"
                              "Connection: close\r\n\r\n";
    httpRequest = malloc(strlen(request_template) + strlen(host) - 2);  // 减去%s的长度
    if (httpRequest == NULL) {
        DieWithError("malloc() failed");
    }
    sprintf(httpRequest, request_template, host);

    // 发送HTTP请求
    if (send(sock, httpRequest, strlen(httpRequest), 0) != strlen(httpRequest)) {
        DieWithError("send() sent unexpected number of bytes");
    }

    // 接收并打印响应
    totalBytesRcvd = 0;
    printf("=== 服务器响应 ===\n");
    while ((bytesRcvd = recv(sock, httpBuffer, RCVBUFSIZE - 1, 0)) > 0) {
        totalBytesRcvd += bytesRcvd;
        httpBuffer[bytesRcvd] = '\0';
        printf("%s", httpBuffer);
    }

    if (bytesRcvd < 0) {
        DieWithError("recv() failed");
    }

    printf("\n=== 接收完成 ===\n");
    printf("总接收字节数: %d\n", totalBytesRcvd);

    free(httpRequest);
    close(sock);
    freeaddrinfo(servinfo);
    exit(0);
}

void DieWithError(char *errorMessage) {
    perror(errorMessage);
    exit(1);
}

关键修改点

  1. 修复连接逻辑:直接使用getaddrinfo返回的addrinfo结构创建socket和发起连接,不再手动构造sockaddr_in,同时支持IPv4和IPv6。
  2. 实现URL信息显示:在getAddressInfo函数中遍历解析结果,打印目标主机、端口以及所有解析到的IP地址(IPv4/IPv6)。
  3. 修复HTTP请求:动态生成Host字段,替换为用户输入的主机名,符合HTTP规范。
  4. 优化缓冲区:增大接收缓冲区,避免截断长响应。

内容的提问来源于stack exchange,提问作者PikaKirbyBro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 14:47:00