大多数浏览器和
Developer App 均支持流媒体播放。
-
通过 HTTP/3 和 QUIC 加快联网速度
网络技术迅速迭代,下一个 HTTP 的主要版本已经出现了。了解 HTTP/3 如何降低延迟并提升 app 的可靠性,弄清其底层传输协议 QUIC 如何利用新的传输功能和多流连接组,在您自己的自定义协议中实现创新性的功能。
资源
相关视频
Tech Talks
WWDC22
WWDC21
-
下载
♪低音音乐声♪ ♪ 瑞保罗:大家好 我是瑞 今天 我和我的同事艾瑞克将讨论 如何使用HTTP/3和QUIC 这是iOS 15和macOS Monterey中 提供的两种新协议 来加速app的网络连接 我们将从探索HTTP的发展 以及HTTP/3如何提高性能开始 我们还会讨论QUIC HTTP/3背后的新传输协议 之后 我们将解释如何在 URLSession中使用HTTP/3 以及如何配置HTTP服务器 以支持HTTP/3 最后 我们将深入研究 使用QUIC的API 以及如何在QUIC上 实现自定义网络协议 让我们从HTTP的发展开始 假设我们需要获取一个资源 我们建立一个连接 发送请求 等待服务器处理它 然后接收响应 现在 如果我们想在 第一个资源完成之前 获取另一个资源 我们又要经历同样的过程 建立连接、发送请求 等待处理、接收响应 这次用深绿色表示 这是第三个资源的 另一个示范 以橙色表示 如图所示 连接设置花费了大量时间 如果我们重用 单个HTTP/1连接会怎样? 我们保存了连接建立时间 但是只有在前一个响应结束后 才能发送请求 这称为队头阻塞 过去 HTTP实现 使用许多并行连接来克服这个问题 并行HTTP连接的数量 甚至可以由app配置 然而 这导致客户端和服务器的 网络行为效率低下 HTTP/2通过在单个连接上 复用多个流来解决队头阻塞问题 请求会提前发送 来自不同流的数据可以交叉发送 这允许更有效地使用单个TCP连接 因为空闲等待时间大大减少 使用HTTP/3 连接建立速度要快得多 所以请求可以更快地发出 然而 这并不是HTTP/3的唯一好处 HTTP/3流是独立的 这与HTTP/2不同 在HTTP/2中 所有流共享一个TCP连接 在大多数网络上 数据包会丢失 这是无线网络上的正常事件 也是检测网络容量的一个自然部分 在HTTP/2中 丢包可能会影响许多流 因为所有HTTP/2流 共享一个TCP连接 在HTTP/3中 只有相应的HTTP流受到影响 属于其他流的数据 可以提前交付 我们刚刚展示了HTTP/3 如何更快地建立连接 以及它如何更好地处理丢包 这些改进是由底层传输协议 实现的:QUIC QUIC是一种新的可靠传输协议 已被因特网工程任务组 标准化 它基于TCP的相同概念 但提供端到端加密 多路复用流和身份验证 QUIC的安全性 建立在著名的TLS1.3协议之上 QUIC的主要好处是提高了性能 让我们来探索 QUIC是如何实现这一点的 QUIC依靠TLS1.3 来执行安全握手 不需要 熟悉的TCP三向交握 将握手时间减少到单次往返 多路复用流是QUIC的一个关键概念 因此它不会受到队头阻塞的影响 QUIC端点能够将有关 它收到的数据包的更复杂信息 传递给另一个端点 并且不受TCP限制的影响 因此QUIC连接可以改进丢失恢复 该协议还支持连接迁移 允许连接在不同网络接口之间 无缝移动 而无需重新建立会话 例如 在蜂窝网络和Wi-Fi之间 如果你想了解更多 关于网络延迟的信息 请观看 《减少app的网络延迟》课程 让我们来谈谈 如何在你的app中使用HTTP/3 如果你使用URLSession 你不需更改你的app 因为iOS 15 和macOS Monterey 默认启用HTTP/3 一旦在你的服务器上启用了HTTP/3 就万事具备了 即将推出的HTTP/3 RFC版本 和早期的HTTP/3草案版本29 都被支持 那么如何确保你的app 使用HTTP/3呢? 让我们用仪器找出答案吧! 在Xcode 13中 我们在网络分析模板中 引入了一种新工具 来检查HTTP流量 它直接使用URLSession 因此不需要设置 我们可以使用仪器来发现 我们的app是否使用HTTP/3 还是更早的HTTP版本 我们将启动一个iOS app 该app在启动时 会获取一组狗图片 然后 我们将检查HTTP标头以了解 以找出服务器是如何发布HTTP/3的 让我们继续并选择网络分析模板
让我们点击左上角的记录 将显示一个提示 表明记录HTTP流量的隐私含意 在我们同意后 仪器将开始记录HTTP事务
接下来 仪器将显示 一个包含每个app 和每个域的所有HTTP事务的图 我们现在已经捕获了 我们需要的所有数据 我们可以点击位于左上角的暂停按钮
选择我们要用的定义域 我们可以通过在HTTP事务上 单击Option键 然后选择域来做到这一点
我们需要配置仪器 来显示HTTP事务的详细信息 要实现这一点 请确保左侧的选单显示 HTTP事务
让我们选择第一个请求 通过向右滚动 我们可以找到标识此事务 HTTP版本列 它标示了该事务 使用的HTTP版本 我们仍在使用HTTP/2 但是为什么呢? 在右侧 我们可以找到 包含响应标头的扩展详细信息视图 这就给了我们答案 服务器使用HTTP替代服务 来宣布对HTTP/3的支持
URLSession不会使用HTTP/3 除非它被发布 在本例中 HTTP/3通过 Alt-Svc HTTP标头进行发布 对于HTTP服务器来说 使用此标头来宣布 对HTTP/3的支持是很常见的 这些信息将用于将来的连接 我们称之为“服务发现” 现在让我们再次录制app
一旦仪器重新启动app 同样的一组HTTP事务就会发生 我们现在可以暂停仪器
让我们再次放大并检查第一个事务 因为我们记得服务器支持HTTP/3 所以我们现在使用HTTP/3 HTTP/3服务发现 对你的app是透明的 HTTP/3服务器支持的发现 有两种方式 推荐的方法是将DNS服务器配置 为通过HTTPS资源记录 发布对HTTP/3的支持 只需配置应用层协议 用h3字符串发布HTTP/3 你也应该配置你的服务器 以添加一个新的标头 使用替代服务来发布HTTP/3 你的服务器应该发送 一个Alt-Svc标头 来发布HTTP/3 这包括端口号和服务的max-age 以秒为单位 DNS记录的优势在于 由于信息在DNS中 一个HTTP/3连接可以在 你的app第一次尝试联系 你的服务器时建立 当你知道你的服务器支持HTTP/3 并且你想加快发现过程时 你可以使用 假设HTTP3Capable属性 这允许HTTP堆栈 假定你有一个HTTP/3服务器 但不保证会使用HTTP/3 网络可能仍会阻塞HTTP/3 或者你的服务器 可能实际上并不支持HTTP/3 在这种情况下 我们将回退到HTTP/2 HTTP允许客户端 为每个资源指定优先级 由于资源通常是相关的 所以优先级允许服务器 根据客户端的需要 先发送一些资源 例如 可以通过对影响网页呈现 最多的资源 进行优先级排序 来改善使用者的网页浏览体验 在HTTP/2中引入了优先级方案 但由于其复杂性 它通常不被重视 因此 旧的优先级模型 从HTTP/3中删除了 HTTP/3堆栈使用了一个新的 更简单的模型 它依赖于HTTP标头 在此模型中 优先级 由紧急参数 零到七 和一个可选的增量交付参数指定的 使用URLSession时 支持优先级的API保持不变 你仍然可以使用priority属性 指定HTTP优先级 该属性使用紧迫性与服务器通信 你可以使用 prefersIncrementalDelivery属性 启用增量交付 默认优先级为三 URLSession根据是否使用了 方便的API 如异步数据方法 来推断增量交付 当你的app下载的内容 在整个资源被下载后 才能被处理时 你应该把这个属性设置为false 还支持在发送请求后 动态更改资源的优先级 例如 你可以以较低的优先级 预取照片 然后当用户导航到 app的该部分时提高该优先级 接下来 我的同事艾瑞克将解释 如何更改自定义网络协议 以采用QUIC 谢谢你 艾瑞克金尼尔:谢谢 瑞! 正如我们之前讨论的 HTTP/3建立在QUIC之上 QUIC提供多路复用流 类似于HTTP/2中的流 但没有共享单个TCP连接 作为底层传输 所带来的问题 QUIC传输连接 或QUIC隧道 可为多个单向 或双向QUIC流复用数据 流可以由任一端点创建 可以同时发送与其他流交错的数据 并且具有类似与TCP提供的 传统流类似的状态 最重要的是 QUIC内置了TLS 1.3安全性 能够更好地响应不断变化的网络条件 这些功能不仅适用于HTTP 如果你的app正在交换 基于非请求/响应的数据 可以从共享底层传输上下文的 多路复用流中受益 或者正在实现任何其他自定义协议 例如点对点通信或RPC调用 考虑使用你的app使用QUIC传输 在iOS 15和macOS Monterey中 NWProtocolQUIC加入了 Network.framework 提供的其他内置协议 创建使用QUIC的连接是非常熟悉的 只需提供你的端点 和新可用的QUIC参数 这些参数指定ALPN字符串 与服务器协商的应用层协议 设置一个状态更新处理程序 就像往常一样 以便能够在连接进展 和准备就绪时做出响应 最后 在希望用于状态更新 和其他回调的分派队列上 启动连接 现在你已经建立了一个QUIC流 你可以像任何其他 NWConnection一样发送和接收数据 使用send函数提供希望 发送到远程端点的数据 并在完成后安排后续发送 使用receive来处理传入的数据 并在接受完成时安排后续接收 去年 我们在 Network.framework中引入了 ConnectionGroup对象 以便更容易地处理 多个连接关联或分组的情况 在底层传输上下文 或隧道上复用的 QUIC流 基于该关系在逻辑上分组 并且可以与新的组类型一起使用: NWMultiplexGroup 连接组遵循与其他 Network.framework对象 类似的生命周期 并允许你推断QUIC流 共享的底层QUIC隧道的状态 它还允许你从特定的QUIC隧道 创建新的传出流 以及接收 由远程端点发起的新传入流 要为多路复用协议创建连接组 请使用多路复用组描述符 在本例中 我们将在端口443上 创建一个到example.com的组描述符 接下来 我们使用该描述符 和QUIC参数 创建一个NWConnectionGroup 并在创建它们时 提供我们的ALPN字符串 就像NWConnection一样 我们设置了一个状态更新处理程序 但这一次 它跟踪底层QUIC隧道的状态 而不是单个流的状态 最后 启动连接组 提供回调队列 可以通过从组初始化 NWConnection 或通过对组调用 提取函数来创建新的传出流 远程端点发起的传入流 可以通过在组上 设置新的连接处理程序 来处理 可以像往常一样 使用状态处理程序设置这些连接 这次是跟踪流状态 并从用于回调的队列开始 就像其他协议一样 你可以在创建参数对象时 使用QUIC.Options进行配置 对于QUIC 你可以配置QUIC规范中 列出的传输参数 也可以自定义从连接组 创建单个流时的属性 例如 如果你想创建一个新的单向流 如果你使用NWListener 在你的app中执行服务器 它也会被增强 允许你通过 newConnectionGroupHandler 接收新的传入QUIC隧道 每当有人建立到服务器的 新QUIC隧道时 你的newConnectionGroupHandler 就会被调用 在该处理程序中 你可以像往常一样设置组 来接收状态更新 这也是设置我们刚刚讨论的 新连接处理程序的好地方 如果你想接收在此隧道上 打开的后续流 请使用用于回调的队列启动组 这样就大功告成了 最后 你可以使用 NWProtocolMetadata 来访问有关流的信息 例如 你可能想要检查 新创建流的流ID 当你完成了一个流 如果你的自定义协议定义了 applicationError代码 你可以使用元数据在你取消流之前 将任何错误传达给远程端点 因此 我们刚刚探索了如何使用 新的NWMultiplexGroup类型 来创建和管理QUIC隧道 并从该组中 为每个QUIC流 创建单独的 NWConnection 我们可以使用NWListener 来监听传入的隧道 并使用产生的连接组 来接收新的传入流 在这些流上 我们可以像在任何其他连接上 一样发送和接收数据 我们可以使用QUIC协议选项 来指定传输参数和配置流 同时使用QUIC协议元数据 来检查流并将 QUIC特定信息传达给远程端点 现在我们已经通过采用QUIC 改进了我们app中的网络 我们如何判断它是否有效? 我们可以在除错时启动我们的app 使用一个新的环境变量 来输出qlog文件 qlog是IETF中提出的一种 新的标准化日志记录格 与传统的数据包捕获相比 它允许你导出关于QUIC 连接行为方式的更丰富的信息 执行测试后 你可以使用 Xcode中的设备窗口 下载带有qlog文件的 app容器以进行分析 并且有许多 不同的开源可视化方法 可以更轻松地 对QUIC连接的行为进行内省 今天 我们研究了HTTP/3 为你的HTTP流量提供的改进 在客户端 对于使用 现代网络API的使用者来说 因此在服务器上启用HTTP/3 以利用其提高的性能 和适应不断变化的网络条件的弹性 如果你正在使用 自定义的非HTTP网络协议 请使用Network.framework中 内置的新多路复用协议支持 来创建与NWConnectionGroup的 QUIC连接 无论你使用哪种协议 你都可以使用新的除错工具 来可视化下一代 网络协议的惊人优点 谢谢收看 ♪
-
-
13:20 - Using QUIC in your app
// Create a connection using QUIC let connection = NWConnection(host: "example.com", port: 443, using: .quic(alpn: ["myproto"])) // Set the state update handler to be notified when the connection is ready connection.stateUpdateHandler = { newState in switch newState { case .ready: print("Connected using QUIC!") default: break } } // Start the connection with callback queue connection.start(queue: queue)
-
15:08 - Establish a tunnel with NWMultiplexGroup
// Establish a tunnel with NWMultiplexGroup // Create a group let descriptor = NWMultiplexGroup(to: .hostPort(host: "example.com", port: 443)) let group = NWConnectionGroup(with: descriptor, using: .quic(alpn: ["myproto"])) // Set the state update handler to be notified when the group is ready group.stateUpdateHandler = { newState in switch newState { case .ready: print("Connected using QUIC!") default: break } } // Start the group with callback queue group.start(queue: queue)
-
15:45 - Manage streams with NWConnectionGroup
// Manage streams with NWConnectionGroup // Create a new outgoing stream let connection = NWConnection(from: group) // Receive new incoming streams initiated by the remote endpoint group.newConnectionHandler = { newConnection in // Set state update handler on incoming stream newConnection.stateUpdateHandler = { newState in // Handle stream states } // Start the incoming stream newConnection.start(queue: queue) }
-
16:43 - Receive incoming QUIC tunnels from NWListener
// Receive incoming QUIC tunnels from NWListener // Set the new connection group handler listener.newConnectionGroupHandler = { group in group.stateUpdateHandler = { newState in // Handle tunnel states } group.newConnectionHandler = { stream in // Set up and start new incoming streams } group.start(queue: queue) }
-
17:22 - Access QUIC metadata
// Access QUIC metadata to learn about and modify streams // Find the stream ID of a particular QUIC stream if let metadata = connection.metadata(definition: NWProtocolQUIC.definition) as? NWProtocolQUIC.Metadata { print("QUIC Stream ID is \(metadata.streamIdentifier)") // Some time later... // Set the application error, if appropriate, before cancelling the stream metadata.applicationError = 0x100 connection.cancel() }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。