首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在swift中获取Ip地址

如何在swift中获取Ip地址
EN

Stack Overflow用户
提问于 2014-09-02 22:41:45
回答 3查看 41.7K关注 0票数 27

如何获取本地IpAddress?

我尝试使用这个Obj C示例:how to get ip address of iphone programmatically

当我到达函数getifaddrs()时,我不能再继续下去了。我不能使用这个函数。

有没有其他方法可以做到这一点,或者我的方法是错误的?

EN

回答 3

Stack Overflow用户

发布于 2016-01-18 04:17:36

回答Is there an alternative way to getifaddrs() for getting the ip-address?的问题

是的,还有另一种方法。您还可以通过使用ioctl()获取ip地址。最干净的方法是用C语言,然后用Swift把它包装起来。因此请考虑以下内容:

创建一个C Source File (Xcode应该将它与.h一起创建),并记住将头部添加到项目的桥头中,或者如果您有一个可可触摸框架,则将头部添加到伞头中。

将以下代码添加到.c源代码中,并将方法声明添加到.h中:

代码语言:javascript
复制
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>

int _interfaceAddressForName(char* interfaceName, struct sockaddr* interfaceAddress) {

    struct ifreq ifr;
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    ifr.ifr_addr.sa_family = AF_INET;

    strncpy(ifr.ifr_name, interfaceName, IFNAMSIZ-1);

    int ioctl_res;
    if ( (ioctl_res = ioctl(fd, SIOCGIFADDR, &ifr)) < 0){
        return ioctl_res;
    }

    close(fd);
    memcpy(interfaceAddress, &ifr.ifr_addr, sizeof(struct sockaddr));
    return 0;
}

你的Swift包装器可能看起来像这样:

代码语言:javascript
复制
public enum Error:ErrorType {
    case IOCTLFailed(Int32)
    case StringIsNotAnASCIIString
}

public func interfaceAddress(forInterfaceWithName interfaceName: String) throws -> sockaddr_in {

    guard let cString = interfaceName.cStringUsingEncoding(NSASCIIStringEncoding) else {
        throw Error.StringIsNotAnASCIIString
    }

    let addressPtr = UnsafeMutablePointer<sockaddr>.alloc(1)
    let ioctl_res = _interfaceAddressForName(strdup(cString), addressPtr)
    let address = addressPtr.move()
    addressPtr.dealloc(1)

    if ioctl_res < 0 {
        throw Error.IOCTLFailed(errno)
    } else {
        return unsafeBitCast(address, sockaddr_in.self)
    }
}

然后,您可以在代码中使用它,如下所示:

代码语言:javascript
复制
let interfaceName = "en0"
do {
    let wlanInterfaceAddress = try interfaceAddress(forInterfaceWithName: interfaceName)
    print(String.fromCString(inet_ntoa(wlanInterfaceAddress.sin_addr))!)
} catch {
    if case Error.IOCTLFailed(let errno) = error where errno == ENXIO {
        print("interface(\(interfaceName)) is not available")
    } else {
        print(error)
    }
}

en0通常是您需要的接口,它代表WLAN

如果您还需要知道可用的接口名称,则可以使用if_indextoname()

代码语言:javascript
复制
public func interfaceNames() -> [String] {

    let MAX_INTERFACES = 128;

    var interfaceNames = [String]()
    let interfaceNamePtr = UnsafeMutablePointer<Int8>.alloc(Int(IF_NAMESIZE))
    for interfaceIndex in 1...MAX_INTERFACES {
        if (if_indextoname(UInt32(interfaceIndex), interfaceNamePtr) != nil){
            if let interfaceName = String.fromCString(interfaceNamePtr) {
                interfaceNames.append(interfaceName)
            }
        } else {
            break
        }
    }

    interfaceNamePtr.dealloc(Int(IF_NAMESIZE))
    return interfaceNames
}
票数 2
EN

Stack Overflow用户

发布于 2018-11-03 18:13:26

代码语言:javascript
复制
   func getIfConfigOutput() -> [String:String] {
    let cmd = "for i in $(ifconfig -lu); do if ifconfig $i | grep -q \"status: active\" ; then echo $i; fi; done"
    let interfaceString = shell(cmd)
    let interfaceArray = interfaceString.components(separatedBy: "\n")
    var finalDictionary:[String:String] = [String:String]()
    for (i,_) in interfaceArray.enumerated() {
        if (interfaceArray[i].hasPrefix("en")){
            let sp = shell("ifconfig \(interfaceArray[i]) | grep \"inet \" | grep -v 127.0.0.1 | cut -d\\  -f2")
          finalDictionary[interfaceArray[i]] = sp.replacingOccurrences(of: "\n", with: "")
        }
    }
  print(finalDictionary)
    return finalDictionary
}
func shell(_ args: String) -> String {
    var outstr = ""
    let task = Process()
    task.launchPath = "/bin/sh"
    task.arguments = ["-c", args]
    let pipe = Pipe()
    task.standardOutput = pipe
    task.launch()
    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    if let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue) {
        outstr = output as String
    }
    task.waitUntilExit()
    return outstr
}

这会对你有帮助。代码返回一个带有与之关联的接口和IP地址的字典。

票数 2
EN

Stack Overflow用户

发布于 2021-09-08 15:58:20

在Swift 5中,您可以直接对Swift使用ioctl,而不是求助于'C‘来获取给定接口的IP地址详细信息。

如下所示:

代码语言:javascript
复制
private enum AddressRequestType {
    case ipAddress
    case netmask
}

// From BDS ioccom.h
// Macro to create ioctl request
private static func _IOC (_ io: UInt32, _ group: UInt32, _ num: UInt32, _ len: UInt32) -> UInt32 {
    let rv = io | (( len & UInt32(IOCPARM_MASK)) << 16) | ((group << 8) | num)
    return rv
}

// Macro to create read/write IOrequest
private static func _IOWR (_ group: Character , _ num : UInt32, _ size: UInt32) -> UInt32 {
    return _IOC(IOC_INOUT, UInt32 (group.asciiValue!), num, size)
}

private static func _interfaceAddressForName (_ name: String, _ requestType: AddressRequestType) throws -> String {
    
    var ifr = ifreq ()
    ifr.ifr_ifru.ifru_addr.sa_family = sa_family_t(AF_INET)
    
    // Copy the name into a zero padded 16 CChar buffer
    
    let ifNameSize = Int (IFNAMSIZ)
    var b = [CChar] (repeating: 0, count: ifNameSize)
    strncpy (&b, name, ifNameSize)
    
    // Convert the buffer to a 16 CChar tuple - that's what ifreq needs
    ifr.ifr_name = (b [0], b [1], b [2], b [3], b [4], b [5], b [6], b [7], b [8], b [9], b [10], b [11], b [12], b [13], b [14], b [15])
    
    let ioRequest: UInt32 = {
        switch requestType {
        case .ipAddress: return _IOWR("i", 33, UInt32(MemoryLayout<ifreq>.size))    // Magic number SIOCGIFADDR - see sockio.h
        case .netmask: return _IOWR("i", 37, UInt32(MemoryLayout<ifreq>.size))      // Magic number SIOCGIFNETMASK
        }
    } ()
    
    if ioctl(socket(AF_INET, SOCK_DGRAM, 0), UInt(ioRequest), &ifr) < 0 {
        throw POSIXError (POSIXErrorCode (rawValue: errno) ?? POSIXErrorCode.EINVAL)
    }
    
    let sin = unsafeBitCast(ifr.ifr_ifru.ifru_addr, to: sockaddr_in.self)
    let rv = String (cString: inet_ntoa (sin.sin_addr))
    
    return rv
}

public static func getInterfaceIPAddress (interfaceName: String) throws -> String {
    return try _interfaceAddressForName(interfaceName, .ipAddress)
}

public static func getInterfaceNetMask (interfaceName: String) throws -> String {
    return try _interfaceAddressForName(interfaceName, .netmask)
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25626117

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档