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

macOS平台下多URL DNS解析的高效并行方案优化问询

macOS 批量DNS解析高效优化方案

1. 优先用异步DNS API:getaddrinfo_a

macOS原生支持POSIX标准的getaddrinfo_a,这是最省心的单线程异步解析方案,完全不用搞多线程。

  • 操作步骤:
    • 先把输入的URL处理成纯域名(比如把https://www.xxx.com/path里的域名抽出来)
    • 给每个域名创建struct gaicb结构,填好域名、服务类型(随便填个80就行,不影响IP解析)和地址类型(比如指定IPv4)
    • 调用getaddrinfo_a(GAI_NOWAIT, 请求列表, 数量, NULL)一次性发所有异步请求
    • 用gai_suspend等着,有请求完成就处理,提取第一个IP,然后继续等剩下的
  • 优势:单线程跑完全部请求,系统帮你处理异步逻辑,内存和CPU占用比多线程低太多,不会有大量线程空等的浪费

2. 自定义异步:kqueue + res_nsend

如果需要自己控制DNS服务器这类细节,可以用macOS的kqueue事件框架配合底层DNS函数res_nsend:

  • 操作步骤:
    • 初始化DNS解析器上下文
    • 给每个域名构造DNS查询包,用非阻塞套接字发请求
    • 把所有套接字加到kqueue里监听读事件
    • 进循环,kqueue触发读事件就去读响应包,解析出第一个IP,处理完关套接字,直到所有请求搞定
  • 优势:完全自己掌控流程,适合有特殊DNS需求的场景,同样单线程,资源效率拉满

关键注意点

  • 一定要先把URL转成纯域名,不然getaddrinfo会解析失败
  • 要处理解析失败的情况,比如域名不存在,得对应输出标记或空值,保证结果和输入URL的顺序完全对应
  • macOS自带DNS缓存,重复解析同一个域名直接拿缓存,不用自己再做缓存浪费资源

示例代码(getaddrinfo_a实现)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <unistd.h>

#define MAX_REQUESTS 1000

int main() {
    // 示例域名列表,实际要从输入的URL提取域名
    const char *hosts[MAX_REQUESTS] = {"www.apple.com", "www.google.com", "www.github.com"};
    int total = 3;

    struct gaicb *reqs[MAX_REQUESTS];
    struct sigevent se = {0};

    // 初始化每个解析请求
    for (int i = 0; i < total; i++) {
        reqs[i] = malloc(sizeof(struct gaicb));
        memset(reqs[i], 0, sizeof(struct gaicb));
        reqs[i]->gaicb_name = hosts[i];
        reqs[i]->gaicb_service = "80";
        reqs[i]->gaicb_hints = malloc(sizeof(struct addrinfo));
        memset(reqs[i]->gaicb_hints, 0, sizeof(struct addrinfo));
        reqs[i]->gaicb_hints->ai_family = AF_INET; // 只获取IPv4地址
        reqs[i]->gaicb_hints->ai_socktype = SOCK_STREAM;
    }

    // 批量发起异步解析请求
    int ret = getaddrinfo_a(GAI_NOWAIT, reqs, total, &se);
    if (ret != 0) {
        perror("getaddrinfo_a 调用失败");
        return 1;
    }

    // 等待并处理结果
    int remaining = total;
    while (remaining > 0) {
        ret = gai_suspend(reqs, total, NULL);
        if (ret == -1) {
            perror("gai_suspend 出错");
            break;
        }

        for (int i = 0; i < total; i++) {
            if (reqs[i] == NULL) continue;

            int err = gai_error(reqs[i]);
            if (err == 0) {
                // 解析成功,提取第一个IPv4地址
                char ip[INET_ADDRSTRLEN];
                inet_ntop(AF_INET, &((struct sockaddr_in*)reqs[i]->gaicb_result->ai_addr)->sin_addr, ip, INET_ADDRSTRLEN);
                printf("%s -> %s\n", hosts[i], ip);

                // 释放资源
                freeaddrinfo(reqs[i]->gaicb_result);
                free(reqs[i]->gaicb_hints);
                free(reqs[i]);
                reqs[i] = NULL;
                remaining--;
            } else if (err != EINPROGRESS) {
                // 解析失败
                printf("%s -> 解析失败: %s\n", hosts[i], gai_strerror(err));

                free(reqs[i]->gaicb_hints);
                free(reqs[i]);
                reqs[i] = NULL;
                remaining--;
            }
        }
    }

    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 03:11:25