简体   繁体   English

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

[英]Swift obtaining ip address from socket returns weird value

I'm trying to obtain the remote ip address using getpeername() under iOS/Swift (real hardware no emulation). 我正在尝试使用iOS / Swift下的getpeername()获取远程ip地址(真正的硬件没有仿真)。

This is what I'm doing: 这就是我正在做的事情:

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

the values that I'm getting are: 我得到的价值是:

socket 7 ip Optional("16.2.209.237")

and that is certainly not the remote address. 那肯定不是远程地址。 Please can someone help me? 请有人帮帮我吗? What I'm doing wrong? 我做错了什么?

The main error is that inet_ntop() takes the address of a struct in_addr (or struct in_addr6 for IPv6), and not the address of a struct sockaddr . 主要错误是inet_ntop()获取struct in_addr的地址struct in_addr (或struct in_addr6用于IPv6),而不是struct sockaddr的地址。

Another error is that the length argument to getpeername() must be the length of the passed socket address structure, you are passing the length of an Int32 . 另一个错误是getpeername()的length参数必须是传递的套接字地址结构的长度,您传递的是Int32的长度。

Your current code passes AF_INET to inet_ntop() and is therefore limited to IPv4 addresses. 您当前的代码将AF_INET传递给inet_ntop() ,因此仅限于IPv4地址。 If that is sufficient for you, the following should work: 如果这对您来说已经足够,以下情况应该有效:

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)

Allocating the socket address structure makes casting between the different pointer types a bit easier. 分配套接字地址结构使得在不同指针类型之间的转换更容易一些。 I have also replaced the variable name socket by sockfd to avoid confusion with the socket() function. 我还用sockfd替换了变量名socket ,以避免与socket()函数混淆。

The more "modern" function to convert socket addresses to strings is getnameinfo() . 将套接字地址转换为字符串的“现代”函数是getnameinfo() The following code demonstrates how to use it. 以下代码演示了如何使用它。 It works for both IPv4 and IPv6 addresses: 它适用于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 update: First method: 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)!)")
    }
}

Second method: 第二种方法:

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

apple sample code https://developer.apple.com/library/ios/samplecode/SimpleTunnel/Listings/tunnel_server_UDPServerConnection_swift.html 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
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM