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 開始存在的。markdown
在將來,Apple 但願你可以將原來的 Socket API 所有替換爲全新的 Network.framework。(iOS 又有人要了!)網絡
Socket 主要使用的三種場景:遊戲聯機、流式視頻傳輸、在線聊天。閉包
getaddrinfo()
查詢 DNSsocket()
setsockopt()
設置 socket 選項connect()
開始 TCP 鏈接NWEndPoint
與 NWParameters
建立鏈接connection.start()
.ready
的狀態在鏈接設置完畢之後,就會進入 準備 狀態。而針對移動設備複雜的網絡狀態,你須要更加智能的創建鏈接。app
而使用 Network.framework ,你能夠十分簡單的對網絡路徑進行配置,好比下面的例子中,指定了僅使用蜂窩網絡、使用 IPv6 協議、與禁止代理。都僅是一行命令就完成了。特別當你須要爲特定鏈接指定鏈接方式時,這個框架能極大提升你的效率。框架
在準備完畢之後,鏈接可能進入 等待 、就緒 或 失敗 狀態。固然在你取消鏈接時也會進入 取消 狀態。socket
該案例使用 UDP 進行視頻的實時傳輸,出於簡化考慮,並未對視頻幀作任何編碼,直接把裸數據封包,並經過 UDP 傳輸。在接收端,解包數據並從新封裝爲視頻幀,直接進行播放。案例中也使用了 Bonjour 服務來進行快速設備配對鏈接。tcp
在監聽端的代碼異常簡單,甚至連 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 專題目錄