gpt4 book ai didi

快速获取地址信息

转载 作者:搜寻专家 更新时间:2023-10-31 22:30:16 24 4
gpt4 key购买 nike

POSIX getaddrinfo 分配稍后必须使用 freeaddrinfo 释放的内存。参见 http://manpages.ubuntu.com/manpages/xenial/en/man3/getaddrinfo.3.html

为了简化 API,我创建了这个函数:

import Foundation

enum SystemError: Swift.Error {
case getaddrinfo(Int32, Int32?)
}

public func getaddrinfo(node: String?, service: String?, hints: addrinfo?) throws -> [addrinfo] {
var err: Int32
var res: UnsafeMutablePointer<addrinfo>?
if var hints = hints {
err = getaddrinfo(node, service, &hints, &res)
} else {
err = getaddrinfo(node, service, nil, &res)
}
if err == EAI_SYSTEM {
throw SystemError.getaddrinfo(err, errno)
}
if err != 0 {
throw SystemError.getaddrinfo(err, nil)
}
defer {
freeaddrinfo(res)
}
var result = [addrinfo]()
var ai = res?.pointee
while ai != nil {
result.append(ai!)
ai = ai!.ai_next?.pointee
}
return result
}

不过,我觉得这个函数不正确。

  • Swift 内存模型如何知道 getaddrinfo 分配内存,以及 Swift 不应该用自己的东西覆盖该内存?
  • Swift 如何知道 freeaddrinfo 删除了整个列表,并且它应该复制出已分配给结果数组的 ai 信息?

getaddrinfo 交互的正确方法是什么?

最佳答案

getaddrinfo 分配的内存(例如 malloc)不会分配给任何其他人同一运行进程动态内存分配函数直到被 freeaddrinfo 释放(例如被 free)。因此 Swift 运行时不会践踏该内存(如果我们假设它没有编程错误,例如错误的指针计算)。

另外struct addrinfo是一个值类型,所以

result.append(ai!)

会将指向的结构的副本附加到数组。

但是还是有问题struct addrinfo的一些成员是指针

public var ai_canonname: UnsafeMutablePointer<Int8>! /* canonical name for hostname */
public var ai_addr: UnsafeMutablePointer<sockaddr>! /* binary address */

它可能指向由 getaddrinfo 分配的内存,因此在 freeaddrinfo 之后无效,并在您的之后取消引用它们函数返回会导致未定义的行为。

因此,您必须将 freeaddrinfo 推迟到不再需要地址列表,或复制信息。这有点麻烦,因为 ai_addr 可能指向一个具有不同长度的 IPv4 或 IPv6 套接字地址结构。

以下代码演示了如何复制地址列表到一组 sockaddr_storage 结构(足够大持有任何IP地址)。此代码尚未经过彻底测试,所以请小心使用。

public func getaddrinfo(node: String, service: String, hints: addrinfo?) throws -> [sockaddr_storage] {
var err: Int32
var res: UnsafeMutablePointer<addrinfo>?
if var hints = hints {
err = getaddrinfo(node, service, &hints, &res)
} else {
err = getaddrinfo(node, service, nil, &res)
}
if err == EAI_SYSTEM {
throw SystemError.getaddrinfo(err, errno)
}
if err != 0 {
throw SystemError.getaddrinfo(err, nil)
}
defer {
freeaddrinfo(res)
}
guard let firstAddr = res else {
return []
}

var result = [sockaddr_storage]()
for addr in sequence(first: firstAddr, next: { $0.pointee.ai_next }) {
var sockAddr = sockaddr_storage()
memcpy(&sockAddr, addr.pointee.ai_addr, Int(addr.pointee.ai_addrlen))
result.append(sockAddr)
}
return result
}

备注:

关于快速获取地址信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39857435/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com