Swift从套接字获取IP地址返回奇怪值

3
我将尝试在iOS/Swift(真实硬件,非仿真)中使用getpeername()获取远程IP地址。
以下是我的操作步骤:
var addr = sockaddr(sa_len: 0, sa_family: 0, sa_data: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
            var len: socklen_t = socklen_t(sizeof(Int32))

                if getpeername(socket, &addr, &len) != -1
                {
                var ipAddressString = [CChar](count:Int(INET_ADDRSTRLEN), repeatedValue: 0)
                inet_ntop(
                    AF_INET ,
                    &addr,
                    &ipAddressString,
                    socklen_t(INET_ADDRSTRLEN))
                println("socket \(socket) ip \(String.fromCString(ipAddressString))")
             }

我得到的值是:

socket 7 ip Optional("16.2.209.237")

这显然不是远程地址。请问有人可以帮我吗?我做错了什么?

2个回答

4
主要错误在于inet_ntop()需要传递struct in_addr(或者IPv6用的struct in_addr6)的地址,而不是struct sockaddr的地址。另一个错误是getpeername()中的长度参数必须是传递的套接字地址结构的长度,你正在传递Int32的长度。你当前的代码将AF_INET传递给inet_ntop(),因此仅限于IPv4地址。如果这对你来说足够了,那么以下代码应该可以工作:
var addr = UnsafeMutablePointer<sockaddr_in>.alloc(1)
var len = socklen_t(sizeofValue(addr.memory))

if getpeername(sockfd, UnsafeMutablePointer(addr), &len) != -1 {
    var ipAddressString = [CChar](count:Int(INET_ADDRSTRLEN), repeatedValue: 0)
    inet_ntop(
        AF_INET ,
        &addr.memory.sin_addr, // <-- main difference here
        &ipAddressString,
        socklen_t(INET_ADDRSTRLEN))
    println("socket \(sockfd) ip \(String.fromCString(ipAddressString)!)")
}
addr.dealloc(1)

分配套接字地址结构使不同指针类型之间的转换更容易。我还将变量名称socket替换为sockfd,以避免与socket()函数混淆。

将套接字地址转换为字符串的“现代”函数是getnameinfo()。以下代码演示了如何使用它。它适用于IPv4和IPv6地址:

var addr = UnsafeMutablePointer<sockaddr_storage>.alloc(1)
var len = socklen_t(sizeofValue(addr.memory))

if getpeername(sockfd, UnsafeMutablePointer(addr), &len) != -1 {

    var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
    if (getnameinfo(UnsafeMutablePointer(addr), socklen_t(addr.memory.ss_len),
        &hostBuffer, socklen_t(hostBuffer.count), nil, 0,
        NI_NUMERICHOST) == 0) {
            let host = String.fromCString(hostBuffer)!
            println("socket \(sockfd) ip \(host)")
    }
}
addr.dealloc(1)

Swift 2更新:第一种方法:

var addr = sockaddr_in()
var len = socklen_t(sizeofValue(addr))

withUnsafeMutablePointer(&addr) {
    if getpeername(sockfd, UnsafeMutablePointer($0), &len) != -1 {
        var ipAddressString = [CChar](count:Int(INET_ADDRSTRLEN), repeatedValue: 0)
        inet_ntop(
            AF_INET ,
            &addr.sin_addr, // <-- main difference here
            &ipAddressString,
            socklen_t(INET_ADDRSTRLEN))
        print("socket \(sockfd) ip \(String.fromCString(ipAddressString)!)")
    }
}

第二种方法:
var addr = sockaddr_storage()
var len = socklen_t(sizeofValue(addr))

withUnsafeMutablePointer(&addr) {
    if getpeername(sockfd, UnsafeMutablePointer($0), &len) != -1 {
        var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
        if (getnameinfo(UnsafeMutablePointer($0), socklen_t(addr.ss_len),
            &hostBuffer, socklen_t(hostBuffer.count), nil, 0,
            NI_NUMERICHOST) == 0) {
                let host = String.fromCString(hostBuffer)!
                print("socket \(sockfd) ip \(host)")
        }
    }
}

2

苹果示例代码https://developer.apple.com/library/ios/samplecode/SimpleTunnel/Listings/tunnel_server_UDPServerConnection_swift.html

这是苹果提供的一个示例代码,用于创建一个UDP服务器连接。您可以在链接中找到详细的代码和说明。
func getEndpointFromSocketAddress(socketAddressPointer: UnsafePointer<sockaddr>) -> (host: String, port: Int)? {
    let socketAddress = UnsafePointer<sockaddr>(socketAddressPointer).memory

    switch Int32(socketAddress.sa_family) {
        case AF_INET:
            var socketAddressInet = UnsafePointer<sockaddr_in>(socketAddressPointer).memory
            let length = Int(INET_ADDRSTRLEN) + 2
            var buffer = [CChar](count: length, repeatedValue: 0)
            let hostCString = inet_ntop(AF_INET, &socketAddressInet.sin_addr, &buffer, socklen_t(length))
            let port = Int(UInt16(socketAddressInet.sin_port).byteSwapped)
            return (String.fromCString(hostCString)!, port)

        case AF_INET6:
            var socketAddressInet6 = UnsafePointer<sockaddr_in6>(socketAddressPointer).memory
            let length = Int(INET6_ADDRSTRLEN) + 2
            var buffer = [CChar](count: length, repeatedValue: 0)
            let hostCString = inet_ntop(AF_INET6, &socketAddressInet6.sin6_addr, &buffer, socklen_t(length))
            let port = Int(UInt16(socketAddressInet6.sin6_port).byteSwapped)
            return (String.fromCString(hostCString)!, port)

        default:
            return nil
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接