2014-07-17 14 views
10

Hızlı bir DNS araması yapmayı çabucak yapmaya çalışıyorum. Şimdiye kadar, burada ben kod şudur: "adresleri" Bu noktadaConvert NSData sockaddr yapısına hızlıca geçin

let hostRef = CFHostCreateWithName(kCFAllocatorDefault, "google.com").takeRetainedValue() 
var resolved = CFHostStartInfoResolution(hostRef, CFHostInfoType.Addresses, nil) 
let addresses = CFHostGetAddressing(hostRef, &resolved).takeRetainedValue() as NSArray 

, her öğe NSArray bir sockaddr yapı sarma bir CFDataRef nesnesidir.

CFDataRef ücretsiz NSData için köprülü olabilir beri

, ben şöyle içlerinden döngü edebilirsiniz:

for address: AnyObject in addresses { 
    println(address) // address is of type NSData. 
} 

Şimdiye kadar iyi (Sanırım). Bu, bir birim testinde çalıştırdığımda geçerli görünen verileri yazdırır. Burada sıkışıp kaldım. Benim yaşamım için, NSData nesnesindeki baytların bir sockaddr yapısına nasıl dönüştürüleceğini anlayamıyorum.

Tip COpaquePointer? Adresindeki address.bytes öğesini c yapısına nasıl dönüştürebilirim? Herhangi bir yardım takdir edildi. Bunu anlamaya çalışırken kafamı duvara çarpıyorum.

cevap

10

için NSData yöntemi getBytes(_, length:) yöntemi kullanmak ve önek & operatörü ile inout parametresine sockaddr yapı geçebilir:

var data: NSData ... 
var address: sockaddr ... 

data.getBytes(&address, length: MemoryLayout<sockaddr>.size) 
Swift 3 Güncel:

let host = CFHostCreateWithName(kCFAllocatorDefault, "google.com" as CFString).takeRetainedValue() 
var resolved = DarwinBoolean(CFHostStartInfoResolution(host, .addresses, nil)) 
let addresses = CFHostGetAddressing(host, &resolved)?.takeUnretainedValue() as! [NSData]? 

if let data = addresses?.first { 
    var storage = sockaddr_storage() 
    data.getBytes(&storage, length: MemoryLayout<sockaddr_storage>.size) 

    if Int32(storage.ss_family) == AF_INET { 
     let addr4 = withUnsafePointer(to: &storage) { 
      $0.withMemoryRebound(to: sockaddr_in.self, capacity: 1) { 
       $0.pointee 
      } 
     } 

     // prints 74.125.239.132 
     print(String(cString: inet_ntoa(addr4.sin_addr), encoding: .ascii)) 
    } 
} 

Güncellendi 6/3/2015: Şimdi bu C yapılar kolayca sıfır başlatıldı olabilir, bu çok daha basit hale gelir:

            
 
             
  let host = CFHostCreateWithName(kCFAllocatorDefault, "google.com").takeRetainedValue() var resolved = CFHostStartInfoResolution(host, .Addresses, nil) let addresses = CFHostGetAddressing(host, &resolved)?.takeUnretainedValue() as! [NSData]? if let data = addresses?.first { var storage = sockaddr_storage() data.getBytes(&storage, length: sizeof(sockaddr_storage)) if Int32(storage.ss_family) == AF_INET { let addr4 = withUnsafePointer(&storage) { UnsafePointer<sockaddr_in>($0).memory } // prints 74.125.239.132 println(String(CString: inet_ntoa(addr4.sin_addr), encoding: NSASCIIStringEncoding)) } } 
            
 


Ne yazık ki bu sockaddr ilk başlatıldı gerektirir. Ayrıntılı bir tartışma için

func makeWithUninitialized<T>(body: inout T ->()) -> T { 
    let ptr = UnsafePointer<T>.alloc(sizeof(T)) 
    body(&ptr.memory) 
    return ptr.move() 
} 

let addr = makeWithUninitialized { (inout addr: sockaddr) in 
    data.getBytes(&addr, length: sizeof(sockaddr)) 
} 

Swift: Pass Uninitialized C Structure to Imported C function

+0

Bu bile basitleştirilmiş olabilir için sadece görmek:

func makeWithUnsafePointer<T>(body: UnsafePointer<T> ->()) -> T { let ptr = UnsafePointer<T>.alloc(sizeof(T)) body(ptr) return ptr.move() } let addr: sockaddr = makeWithUnsafePointer { data.getBytes($0 as UnsafePointer<sockaddr>, length: sizeof(sockaddr)) } 

Ya da bu: Bunu önlemek için böyle bir şey yapabileceğini data.getBytes (& addr, uzunluk: sizeof (sockaddr)) – kgreenek

+0

İyi nokta. Cevabımı güncelledim ve ayrıca ilk önce yapıyı başlatmadan aynı şeyi yapmakla ilgili bilgiler ekledim. – jtbandes

+2

Değeri için, muhtemelen sockaddr kullanmak istemezsiniz - ama gerçek sockaddr yapısına sahip olursunuz. Sockaddr_in veya sockaddr_un gibi. Aksi takdirde büyük olasılıkla bir arabellek taşması olur. Belki de bu eklentiyi faydalı buluyorsunuz: https://github.com/AlwaysRightInstitute/SwiftSockets/blob/master/ARISockets/SocketAddress.swift – hnh