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

时间:2015-03-27 06:20:51

标签: sockets swift

我正在尝试使用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 个答案:

答案 0 :(得分:4)

主要错误是inet_ntop()获取struct in_addr的地址 (或struct in_addr6表示IPv6),而不是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()函数混淆。

更多&#34;现代&#34;将套接字地址转换为字符串的函数是 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)")
        }
    }
}

答案 1 :(得分:2)

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

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
    }
}