WWDC18 Session 715 Introducing Network.framework: A modern alternative to Sockets編程
提及 Socket ,我回頭望了一眼書架上厚厚的 UNIX 網絡編程 卷1: 套接字聯網 API(第 3 版) ,而她的姊妹進程間通訊我連塑封膜都沒拆開。的確,這套最先來自 BSD 的 API 很讓人頭疼。雖然她們依然是跨平臺程序的最佳選擇,可是我想應該沒有哪一個小夥伴在項目中會有勇氣從這些 API 開始構築,至少是 CFNetwork 或者 NSNetwork 中的現成接口。更通常性的是選一些面向對象的第三方庫,好比老牌的 CocoaAsyncSocket。固然做爲 Swift 老法師我也會推薦你看看 IBM 出品的 BlueSocket。swift
Socket 編程有不少須要解決的問題,最重要的 3 個大問題,以及更多的細節問題:安全
當前,URLSession 底層就是使用 Network.framework 完成基礎鏈接的。特意查了一下,相關私有 API 是從 iOS 9 開始存在的。網絡
在將來,Apple 但願你可以將原來的 Socket API 所有替換爲全新的 Network.framework。(iOS 又有人要了!)閉包
Socket 主要使用的三種場景:遊戲聯機、流式視頻傳輸、在線聊天。app
getaddrinfo()
查詢 DNSsocket()
setsockopt()
設置 socket 選項connect()
開始 TCP 鏈接NWEndPoint
與 NWParameters
建立鏈接connection.start()
.ready
的狀態在鏈接設置完畢之後,就會進入 準備 狀態。而針對移動設備複雜的網絡狀態,你須要更加智能的創建鏈接。框架
而使用 Network.framework ,你能夠十分簡單的對網絡路徑進行配置,好比下面的例子中,指定了僅使用蜂窩網絡、使用 IPv6 協議、與禁止代理。都僅是一行命令就完成了。特別當你須要爲特定鏈接指定鏈接方式時,這個框架能極大提升你的效率。socket
在準備完畢之後,鏈接可能進入 等待 、就緒 或 失敗 狀態。固然在你取消鏈接時也會進入 取消 狀態。tcp
該案例使用 UDP 進行視頻的實時傳輸,出於簡化考慮,並未對視頻幀作任何編碼,直接把裸數據封包,並經過 UDP 傳輸。在接收端,解包數據並從新封裝爲視頻幀,直接進行播放。案例中也使用了 Bonjour 服務來進行快速設備配對鏈接。ide
在監聽端的代碼異常簡單,甚至連 Bonjour 服務也已經整合好了。你要作的僅僅是指定 .udp
並指定正確的 Bonjour 服務名稱。
單幀發送
// Send a single frame
func sendFrame(_ connection: NWConnection, frame: Data) {
// The .contentProcessed completion provides sender-side back-pressure
connection.send(content: frame, completion: .contentProcessed { (sendError) in
if let sendError = sendError {
// Handle error in sending
} else {
// Send has been processed, send the next frame
let nextFrame = generateNextFrame()
sendFrame(connection, frame: nextFrame)
}
})
}
複製代碼
使用 batch
發送多個數據報
// Hint that multiple datagrams should be sent as one batch
connection.batch {
for datagram in datagramArray {
connection.send(content: datagramArray, completion: .contentProcessed { (error) in
// Handle error in sending
}
})
}
複製代碼
在接收時,提供了方便的方法來讀取消息頭
// Read one header from the connection
func readHeader(connection: NWConnection) {
// Read exactly the length of the header
let headerLength: Int = 10
connection.receive(minimumIncompleteLength: headerLength, maximumLength: headerLength) { (content, contentContext, isComplete, error) in
if let error = error {
// Handle error in reading
} else {
// Parse out body length
readBody(connection, bodyLength: bodyLength)
}
}
}
// Follow the same pattern as readHeader() to read exactly the body length
func readBody(_ connection: NWConnection, bodyLength: Int) { ... }
複製代碼
在全部 TCP 鏈接中 ECN 是默認開啓的。
在 UDP 鏈接中爲每一個數據包標記 ECN 的方法:
let ipMetadata = NWProtocolIP.Metadata()
ipMetadata.ecn = .ect0
let context = NWConnection.ContentContext(identifier: "ECN", metadata: [ ipMetadata ])
connection.send(content: datagram, contentContext: context, completion: .contentProcessed{..})
複製代碼
爲整個鏈接更改服務等級
let parameters = NWParameters.tls
parameters.serviceClass = .background
複製代碼
爲每一個 UDP 數據包更改服務等級
let ipMetadata = NWProtocolIP.Metadata()
ipMetadata.serviceClass = .signaling
let context = NWConnection.ContentContext(identifier: "Signaling", metadata: [ ipMetadata ])
connection.send(content: datagram, contentContext: context, completion: .contentProcessed{..})
複製代碼
容許在鏈接上快速打開須要發送冪等數據
parameters.allowFastOpen = true
let connection = NWConnection(to: endpoint, using: parameters)
connection.send(content: initialData, completion: .idempotent)
connection.start(queue: myQueue)
複製代碼
能夠手動啓用 TCP Fast Open 以經過 TFO 運行 TLS
let tcpOptions = NWProtocolTCP.Options()
tcpOptions.enableFastOpen = true
複製代碼
主動使用失效的 DNS 查詢結果
parameters.expiredDNSBehavior = .allow
let connection = NWConnection(to: endpoint, using: parameters)
connection.start(queue: myQueue)
複製代碼
新的 DNS 查詢會同步進行
.waiting
狀態暗示鏈接還未創建NWParameters
限制鏈接類型主要是兩個狀態,一個是 isViable
當前鏈接是否可用,一個是 betterPathAvailable
是否有更佳的鏈接路徑。她們也都提供了相應的閉包來處理
// Handle connection viability
connection.viabilityUpdateHandler = { (isViable) in
if (!isViable) {
// Handle connection temporarily losing connectivity
} else {
// Handle connection return to connectivity
}
}
// Handle better paths
connection.betterPathUpdateHandler = { (betterPathAvailable) in
if (betterPathAvailable) {
// Start a new connection if migration is possible
} else {
// Stop any attempts to migrate
}
}
複製代碼
CoreFoundation 中 CFStream
綁定的相關方法及 CFSocket
Foundation 中與 NSStream
綁定、NSNetService
監聽、NSSocketPort
以及 SystemConfiguration 中的 SCNetworkReachability
。
固然是 URLSession
和 Network.framework。
查看更多 WWDC 18 相關文章請前往 老司機x知識小集xSwiftGG WWDC 18 專題目錄