如何正確的獲取 DNS 地址

通常狀況下,獲取本機 DNS 地址的時候,咱們會使用如下的方法。html

先在系統中加入 libresolv.tbd 庫。 而後在頭文件中引入如下幾個頭文件:服務器

#include <arpa/inet.h>
#include <ifaddrs.h>
#include <resolv.h>
#include <dns.h>
複製代碼

而後使用如下代碼,或者以此進行改編:markdown

NSMutableArray *DNSList = [NSMutableArray array];
res_state res = malloc(sizeof(struct __res_state));
int result = res_ninit(res);
if (result == 0) {
    for (int i=0;i < res->nscount;i++) {
        NSString *s = [NSString stringWithUTF8String:inet_ntoa(res->nsaddr_list[i].sin_addr)];
        [DNSList addObject:s];
    }
}
res_nclose(res);
free(res);
// dnsList 就是 DNS 服務器地址
複製代碼

可是不巧,不就有個朋友告訴我,使用這段代碼會形成內存泄漏,我本身試了一下,還真有,那是哪裏出了問題呢?oracle

查找過程

通過初步的檢測,發現 int result = res_ninit(res); 這段代碼建立的內存沒有釋放掉。函數

可是下面明明已經寫了 res_nclose(res); 了啊。oop

沒辦法,我點擊進入 res_ninit 的頁面,挨個進行查找。ui

終於在通過了漫長的翻閱資料以後,發現了一份 Oracle 的文檔this

裏面有幾段註釋讓我如獲至寶:spa

  1. The res_ndestroy() function should be called to free memory allocated by res_ninit() after the last use of statp.code

  2. The res_nclose() function closes any open files referenced through statp.

  3. The res_ndestroy() function calls res_nclose(), then frees any memory allocated by res_ninit() referenced through statp.

以及下面這段示例代碼:

#include <resolv.h>
#include <string.h>

int main(int argc, char **argv) {
    int len;
    struct __res_state statp;
    union msg {
        uchar_t buf[NS_MAXMSG];
        HEADER  h;
    } resbuf;

    /* Initialize resolver */
    memset(&statp, 0, sizeof(statp));
    if (res_ninit(&statp) < 0) {
        fprintf(stderr, "Can't initialize statp.\n");
        return (1);
    }

    /* * Turning on DEBUG mode keeps this example simple, * without need to output anything. */
    statp.options |= RES_DEBUG;

    /* Search for A type records */
    len = res_nsearch(&statp, "example.com", C_IN, T_A,
         resbuf.buf, NS_MAXMSG);
    if (len < 0) {
        fprintf(stderr, "Error occured during search.\n");
        return (1);
    }
    if (len > NS_MAXMSG) {
        fprintf(stderr, "The buffer is too small.\n");
        return (1);
    }

    /* ... Process the received answer ... */

    /* Cleanup */
    res_ndestroy(&statp);
    return (0);
}
複製代碼

意思就是:

  • dns 的相關信息存儲於 statp 中,使用 res_ninit 去建立這個 statp,而後能夠從衆讀取數據。
  • res_nclose 函數會關閉全部打開的 statp 文件,可是並不會釋放這部分的內存;若是要關閉的同時釋放掉內存,應該使用 res_ndestroy 函數。

正確代碼

NSMutableArray *DNSList = [NSMutableArray array];
res_state res = malloc(sizeof(struct __res_state));
int result = res_ninit(res);
if (result == 0) {
    for (int i=0;i < res->nscount;i++) {
        NSString *s = [NSString stringWithUTF8String:inet_ntoa(res->nsaddr_list[i].sin_addr)];
        [DNSList addObject:s];
    }
}
res_ndestroy(res);
free(res);
// dnsList 就是 DNS 服務器地址
複製代碼

引用

man pages section 3: Networking Library Functions

相關文章
相關標籤/搜索