swift macos networking ip

Cómo obtener la dirección IP en Swift



macos networking (3)

¿Cómo obtengo mi IpAddress local?

Traté de usar este ejemplo de Obj C : cómo obtener la dirección IP del iPhone mediante programación

Cuando llego a la función getifaddrs() no puedo seguir adelante. No puedo usar la función.

¿Hay una forma alternativa de hacer esto, o me estoy acercando a esto de la manera incorrecta?


Como resultó en la discusión, OP necesita la dirección de la interfaz en una Mac y no en un dispositivo iOS como pensé inicialmente. El código al que se hace referencia en la pregunta verifica el nombre de la interfaz "en0", que es la interfaz WiFi en el iPhone. En una Mac, tiene más sentido comprobar si hay alguna interfaz "en funcionamiento". Por lo tanto, he reescrito la respuesta. Ahora es una traducción rápida del código en Detectar cualquier red conectada .

getifaddrs() se define en <ifaddrs.h> , que no está incluido por defecto. Por lo tanto, debe crear un encabezado de puente y agregar

#include <ifaddrs.h>

La siguiente función devuelve una matriz con los nombres de todas las interfaces de red locales "en funcionamiento".

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 }

Actualización para Swift 3: además de adoptar el código para los muchos cambios en Swift 3 , la iteración en todas las interfaces ahora puede usar la nueva función de sequence() generalizada sequence() :

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 }


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

Sí, hay una forma alternativa. También puede obtener la dirección IP utilizando ioctl() . La forma más limpia sería hacerlo en C y luego envolverlo en Swift. Entonces considera esto:

Cree un C Source File (Xcode debería crearlo junto con un .h) y recuerde agregar el encabezado en el encabezado puente de su proyecto, o en el encabezado paraguas si tiene un marco táctil de cacao.

Agregue lo siguiente en su fuente .c y la declaración del método en .h:

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

Su envoltorio Swift podría verse más o menos así:

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

Luego puede usarlo en su código como:

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 normalmente es la interfaz que necesita, que significa WLAN

Si también necesita conocer los nombres de interfaz disponibles, puede utilizar if_indextoname() :

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 }


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 }

Esto te ayudara. El código devuelve un diccionario con interfaces y direcciones IP asociadas a él.