【问题标题】:How does `gethostbyname` return `struct hostent *` without requiring the caller to release the resource?`gethostbyname` 如何在不要求调用者释放资源的情况下返回 `struct hostent *`?
【发布时间】:2012-07-18 15:03:11
【问题描述】:
struct hostent *gethostbyname(const char *name)

请注意,hostent.h_addr_list 是一个长度可变的字段。

函数gethostbyname如何实现返回指向结构的指针但不需要调用者释放资源?

R. Stevens 著名的《Unix Network Programming Vol 1》一书中使用的所有示例都没有包含释放这些返回指针的代码,我认为这些不是无知的。来自 MSDN 的一个例子也做了同样的事情 example of usage

【问题讨论】:

  • 这是您应该切换到getaddrinfo 的原因之一,它是gethostbyname 的现代版本。调用getaddrinfo后,你必须freeaddrinfo

标签: c network-programming


【解决方案1】:

您链接到的man 页面包含答案:

非NULL时,返回值可能指向静态数据,见 备注如下。

稍后:

函数 gethostbyname() 和 gethostbyaddr() 可以返回指向静态数据的指针, 这可能会被以后的调用覆盖。

【讨论】:

    【解决方案2】:

    假设一个实现想要处理任意大的地址列表,它可以这样做:

    struct hostent *gethostbyname(const char *name) {
        static struct hostent *results = 0;
        static size_t resultsize = 0;
        size_t count = get_count_of_addresses(name)
        if (count > resultsize) {
            struct hostent *tmp = realloc(results, N * count + M);
            if (tmp) {
                results = tmp;
                resultsize = count;
            } else {
                // handle error, I can't remember what the docs say
            }
        }
        fill_in_hostent(results, name);
        return results;
    };
    

    或者,套接字库可以在退出时释放results(例如安装atexit 处理程序),以避免调试工具报告内存泄漏。

    我忽略了地址计数在调整结构大小和填充结构之间可能发生变化的可能性——实际上,您会取回 DNS 结果,然后对其进行处理,因此这是不可能的.我将其保留为两个单独的调用,以避免为 DNS 结果引入伪代码表示。

    【讨论】:

      【解决方案3】:

      可能指向静态内存。如果要保留多个结果,则需要对其进行深层复制。不是浅拷贝,因为该结构本身包含指针。

      注意线程安全。

      【讨论】:

      • 正如我在 OP 中指出的,结构 hostent 中的 h_add_list 字段具有不同的长度。这意味着必须为静态结构分配足够的空间来保存潜在的长 IP 列表。
      • 这可能是真的,但请注意文档和我的回答,说“可能”是静态的。在某些情况下,结构是动态创建的以适应异常长度,但使用静态内存来满足典型情况和性能。
      【解决方案4】:

      它可能指向静态内存,即每次调用它都是同一个指针。

      【讨论】:

        【解决方案5】:

        MS 告诉我们https://msdn.microsoft.com/en-us/library/windows/desktop/ms738524%28v=vs.85%29.aspx

        The memory for the hostent structure returned by the 
        gethostbyname function is allocated internally by the 
        Winsock DLL from thread local storage. Only a single 
        hostent structure is allocated and used, no matter how 
        many times the gethostbyaddr or gethostbyname functions 
        are called on the thread
        

        所以它在 Windows 上是线程安全的,但是...

        它已从 POSIX 中删除,man7.org 告诉我们,在 Linux 上,主机名区域设置不是线程安全的。 http://man7.org/linux/man-pages/man3/gethostbyname.3.html

        ..MS 告诉我们

        The gethostbyname function has been deprecated 
        by the introduction of the getaddrinfo function
        

        不幸的是,替换(getaddrinfo,大多数平台上的线程安全)不是套接字 1.x 的一部分,并且在旧平台上不可用。

        【讨论】:

          猜你喜欢
          • 2016-02-07
          • 1970-01-01
          • 1970-01-01
          • 2013-01-25
          • 1970-01-01
          • 2022-10-16
          • 2014-07-12
          • 1970-01-01
          • 2023-03-31
          相关资源
          最近更新 更多