it-swarm.com.de

So erreichen Sie schnell die IP-Adresse

Wie erhalte ich meine lokale IpAddress?

Ich habe versucht, dieses Obj C-Beispiel zu verwenden: wie man die IP-Adresse des Iphone programmatisch erhält

Wenn ich zur Funktion getifaddrs() komme, komme ich nicht weiter. Ich kann die Funktion nicht verwenden.

Gibt es einen alternativen Weg, oder gehe ich den falschen Weg?

21
Mads Gadeberg

Wie sich in der Diskussion herausgestellt hat, benötigt OP die Schnittstellenadresse auf einem Mac und nicht auf einem iOS-Gerät, wie ich anfangs dachte. Der Code, auf den in der Frage verwiesen wird, prüft, ob der Schnittstellenname "en0", der WLAN-Schnittstelle des iPhone, ist. Auf einem Mac macht es mehr Sinn, stattdessen nach "Up-and-running" -Interface zu suchen. Daher habe ich die Antwort umgeschrieben. Es ist jetzt eine schnelle Übersetzung des Codes in Erkennen eines verbundenen Netzwerks .


getifaddrs() ist in <ifaddrs.h> definiert, das standardmäßig nicht enthalten ist . Daher müssen Sie einen Bridging-Header erstellen und hinzufügen

#include <ifaddrs.h>

Die folgende Funktion gibt ein Array mit den Namen aller lokalen "laufenden" Netzwerkschnittstellen zurück.

func getIFAddresses() -> [String] {
    var addresses = [String]()

    // Get list of all interfaces on the local machine:
    var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
    if getifaddrs(&ifaddr) == 0 {

        // For each interface ...
        var ptr = ifaddr
        while ptr != nil {
            defer { ptr = ptr.memory.ifa_next } 

            let flags = Int32(ptr.memory.ifa_flags)
            let addr = ptr.memory.ifa_addr.memory

            // Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
            if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
                if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {

                    // Convert interface address to a human readable string:
                    var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
                    if (getnameinfo(ptr.memory.ifa_addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
                        nil, socklen_t(0), NI_NUMERICHOST) == 0) {
                        if let address = String.fromCString(hostname) {
                            addresses.append(address)
                        }
                    }
                }
            }
        }
        freeifaddrs(ifaddr)
    }

    return addresses
}

Update für Swift 3: Zusätzlich zur Übernahme des Codes in die viele Änderungen in Swift 3 kann....., Das über alle Schnittstellen läuft, jetzt auch die neue generalisierte sequence() Funktion:

func getIFAddresses() -> [String] {
    var addresses = [String]()

    // Get list of all interfaces on the local machine:
    var ifaddr : UnsafeMutablePointer<ifaddrs>?
    guard getifaddrs(&ifaddr) == 0 else { return [] }
    guard let firstAddr = ifaddr else { return [] }

    // For each interface ...
    for ptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
        let flags = Int32(ptr.pointee.ifa_flags)
        let addr = ptr.pointee.ifa_addr.pointee

        // Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
        if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
            if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {

                // Convert interface address to a human readable string:
                var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
                if (getnameinfo(ptr.pointee.ifa_addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
                                nil, socklen_t(0), NI_NUMERICHOST) == 0) {
                    let address = String(cString: hostname)
                    addresses.append(address)
                }
            }
        }
    }

    freeifaddrs(ifaddr)
    return addresses
}
42
Martin R

Antworten auf Is there an alternative way to getifaddrs() for getting the ip-address?

Ja, es gibt einen alternativen Weg. Sie können die IP-Adresse auch mit ioctl() abrufen. Der sauberste Weg wäre es in C zu tun und dann in Swift einzuwickeln. Also bedenken Sie folgendes:

Erstellen Sie einen C Source File (Xcode sollte es zusammen mit einer .h erstellen), und denken Sie daran, den Header im Bridging-Header Ihres Projekts oder im Umbrella-Header hinzuzufügen, wenn Sie ein Kakao-Touch-Framework haben. 

Fügen Sie der .c-Quelle und der Methodendeklaration Folgendes in .h hinzu:

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

Ihr Swift-Wrapper könnte ungefähr so ​​aussehen:

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

Dann können Sie es in Ihrem Code verwenden:

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 ist normalerweise die von Ihnen benötigte Schnittstelle, die für WLAN steht.

Wenn Sie auch die verfügbaren Schnittstellennamen kennen müssen, können Sie if_indextoname() verwenden:

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

Das wird dir helfen. Code gibt ein Wörterbuch mit damit verbundenen Schnittstellen und IP-Adressen zurück.

1
sudarshan Mane