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 专题目录