ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SwiftNIO 完全指南:事件驱动非阻塞网络框架的架构、模块与实战上手

SwiftNIO 完全指南:事件驱动非阻塞网络框架的架构、模块与实战上手 后端网络【免费下载链接】swift-nioEvent-driven network application framework for high performance protocol servers clients, non-blocking.项目地址https://gitcode.com/gh_mirrors/sw/swift-nio点击查看免费下载SwiftNIO 是 Apple 开源的跨平台异步事件驱动网络应用框架用于快速开发可维护的高性能协议服务器与客户端。本文以仓库根目录 README.md 为主体结合仓库内核心源码如 EventLoop.swift、Bootstrap.swift、MultiThreadedEventLoopGroup.swift与示例程序如 NIOEchoServer系统讲解 SwiftNIO 的模块划分、核心概念、设计哲学、快速上手与开发前置条件帮助你从零开始掌握这一框架并看懂其底层运行原理。SwiftNIO 是什么面向高性能网络服务的低层构建块SwiftNIO 本质上是一个用于构建高性能网络应用的低层工具。它特别针对每连接一线程thread-per-connection并发模型在效率和可行性上无法满足的场景例如承载大量低利用率连接如 HTTP 服务器时为每个连接创建一个线程的开销会迅速失控。它的名字直接来源于其核心手段——非阻塞 I/Onon-blocking I/O。与传统阻塞 I/O 模型不同应用并不会主动等待数据发送或接收完成相反SwiftNIO 请求内核在 I/O 操作可以无阻塞执行时通知它。这种让内核来叫醒我们的模型正是高性能网络框架的关键。一个常见的类比是SwiftNIO 之于 Swift就像 Netty 之于 Java。但需要强调的是SwiftNIO 并不打算提供像 Web 框架那样的高层解决方案。大多数用户构建 Web 应用时不会直接使用 SwiftNIO而是使用 Swift 生态中的众多 Web 框架这些 Web 框架则可能在底层选择 SwiftNIO 来提供网络支持。SwiftNIO 的定位就是给上层应用的建筑材料。仓库组织与模块全景SwiftNIO 项目并非单一仓库而是按功能拆分为多个仓库各仓库独立版本演进仓库功能NIO 2 版本要求swift-nio本仓库SwiftNIO 核心from: 2.0.0swift-nio-sslTLSSSL支持from: 2.0.0swift-nio-http2HTTP/2 支持from: 1.0.0swift-nio-extrasSwiftNIO 周边实用扩展from: 1.0.0swift-nio-transport-servicesmacOS、iOS、tvOS、watchOS 一等公民支持from: 1.0.0swift-nio-sshSSH 支持.upToNextMinor(from: 0.2.0)swift-nio-quicQUIC 支持积极开发中branch: mainswift-nio-http3HTTP/3 支持积极开发中branch: main本仓库swift-nio内部则通过 SwiftPM 打包了多个产品其定义可在 Package.swift 中逐一找到对应 targetNIO伞形umbrella模块导出NIOCore、NIOEmbedded和NIOPosix。NIOCore提供使用 SwiftNIO 所需的核心抽象与类型后文概念概述将详述。大多数提供新EventLoop、Channel或新协议实现的 NIO 扩展项目通常只需依赖NIOCore。NIOPosix为 POSIX 系统提供主要的EventLoopGroup、EventLoop和Channel实现是高性能核心 I/O 层。一般来说只有打算真正做 I/O 的项目如高层协议实现或应用才需要导入它。NIOEmbedded提供EmbeddedChannel和EmbeddedEventLoop是NIOCore抽象的实现可对执行过程进行细粒度控制。最常用于测试也可用于在完全脱离网络的情况下驱动协议实现。NIOConcurrencyHelpers提供 NIO 实现使用的一些低层并发原语如锁和原子操作。NIOFoundationCompat扩展多个 NIO 类型以便与 Foundation 数据类型如Data互操作当处理 Foundation 数据类型时应当导入它。NIOTLS提供用于对接多种 TLS 实现的通用抽象类型。注意它本身不提供 TLS具体实现请查阅 swift-nio-ssl 与 swift-nio-transport-services。NIOHTTP1低层 HTTP/1.1 协议实现。NIOWebSocket低层 WebSocket 协议实现。NIOTestUtils为使用 SwiftNIO 的项目提供测试辅助工具。_NIOFileSystem提供与文件系统交互的asyncAPI该模块在仓库内对应Sources/_NIOFileSystem目录另有一个纯 Swift 的NIOFS模块同样实现了文件系统功能。从源码看Package.swift中NIOCore依赖了NIOConcurrencyHelpers、_NIOBase64、各平台 C 模块CNIOOpenBSD/CNIOFreeBSD/CNIODarwin/CNIOLinux/CNIOWindows/CNIOWASI以及 swift-collections、swift-atomics 等第三方库NIOPosix则额外依赖CNIOPosix。这一分层保证了协议实现只需依赖 NIOCore实际 I/O 才需要 NIOPosix的架构意图。协议实现生态低层与高层两条路线README 列出了一批基于 SwiftNIO 构建的协议实现非穷举。这些库的 I/O 全部以非阻塞方式通过 SwiftNIO 完成其中一部分属于 SwiftNIO 官方项目另一部分则被接受进入了 SSWGSwift Server Work Group的孵化流程。低层协议实现低层协议实现通常是一组ChannelHandler的组合实现协议本身但仍要求用户对 SwiftNIO 有良好理解这类实现往往会被高层库包装成更友好的 API协议客户端服务器模块说明HTTP/1✅✅NIOHTTP1官方 NIO 项目本仓库内HTTP/2✅✅NIOHTTP2官方 NIO 项目swift-nio-http2WebSocket✅✅NIOWebSocket官方 NIO 项目本仓库内TLS✅✅NIOSSL官方 NIO 项目swift-nio-sslSSH✅✅NIOSSH官方 NIO 项目swift-nio-ssh高层实现高层实现通常是不暴露 SwiftNIOChannelPipeline的库用户几乎不需要或完全不需要SwiftNIO 专门知识即可使用但底层 I/O 仍由 SwiftNIO 完成协议客户端服务器模块说明HTTP✅❌AsyncHTTPClientSSWG 社区项目gRPC✅✅GRPC也提供低层 APISSWG 社区项目APNS✅❌APNSwiftSSWG 社区项目PostgreSQL✅❌PostgresNIOSSWG 社区项目Redis✅❌RediStackSSWG 社区项目版本支持、平台与兼容性策略SwiftNIO 2当前主线SwiftNIO 2 是当前版本将在可预见的未来持续维护。官方承诺支持最新发布的 Swift 版本及其之前最近的两个次要版本除非单代码库无法做到同时还会对最新 beta 版和 nightly Swift 构建运行检查。不同 SwiftNIO 版本对应的最低 Swift 版本如下SwiftNIO最低 Swift 版本2.0.0 .. 2.30.05.02.30.0 .. 2.40.05.22.40.0 .. 2.43.05.42.43.0 .. 2.51.05.5.22.51.0 .. 2.60.05.62.60.0 .. 2.65.05.72.65.0 .. 2.76.05.82.76.0 .. 2.83.05.92.83.0 .. 2.87.05.102.87.0 .. 2.98.06.02.98.0 ...6.1本仓库的 Package.swift 使用swift-tools-version:6.1与2.98.0 起要求 Swift 6.1的策略一致。SwiftNIO 1已停止维护SwiftNIO 1 被视为生命周期结束EOL核心 NIO 团队不再积极维护不会增加新功能但修复 bug 或安全漏洞的 PR 在 2022 年 5 月底之前仍会被接受。最新发布的 SwiftNIO 1 版本支持 Swift 4.0、4.1、4.2 和 5.0。如有迁移需求可参考仓库内专门编写的 迁移指南。支持的平台SwiftNIO 的目标是支持所有 Swift 可运行平台目前主要在 macOS 和 Linux 上开发测试已知支持Ubuntu 18.04macOS 10.9、iOS 7配合 swift-nio-transport-services 时为 macOS 10.14、iOS 12、tvOS 12 或 watchOS 6此外SwiftNIO 在 OpenBSD 上提供实验性支持除_NIOFileSystem之外的所有 SwiftNIO 库都可在 OpenBSD 上使用只需在Package.swift中把依赖加上即可。兼容性策略SemVer 与 Public APISwiftNIO 遵循 SemVer 2.0.0 界定公开 API。这意味着你可以用从所需最低版本一直到下一个大版本不含的版本区间来依赖 SwiftNIO。在 SwiftPM 中例如写from: 2.0.0即表示接受从 2.0.0 起、排除 3.0.0 的所有版本。SemVer 与 Public API 保证意味着无需对每个版本逐一测试兼容性也能得到可正常工作的程序。概念概述SwiftNIO 的 8 大基本构件所有 SwiftNIO 应用最终都由以下 8 类对象构成全部由NIOCore提供除 Bootstrap 是若干相关结构体EventLoopGroup协议EventLoop协议Channel协议ChannelHandler协议Bootstrap若干相关结构体ByteBuffer结构体EventLoopFuture泛型类EventLoopPromise泛型结构体下面逐一展开。EventLoop 与 EventLoopGroup一切工作的调度中心EventLoop是 SwiftNIO 的基本 I/O 原语它等待事件通常是 I/O 相关事件如收到数据然后在事件发生时触发某种回调。在几乎所有 SwiftNIO 应用中事件循环的数量都很少——通常每个想使用的 CPU 核心只有一两个。事件循环通常贯穿应用整个生命周期在一个无限循环中持续分发事件。事件循环被聚合成事件循环组group。组的职责是在多个事件循环间分发工作例如监听入站连接时监听 socket 会注册到某个事件循环上但我们并不希望被接受的连接都注册到同一个事件循环那会让一个循环过载、其他循环空闲于是组提供了跨循环分散负载的能力。在源码中EventLoop协议的定义位于 Sources/NIOCore/EventLoop.swift#L246public protocol EventLoop: EventLoopGroup它要求实现者提供inEventLoop判断当前NIOThread是否就是该事件循环绑定的线程主要用于优化快速路径不能当作正确性保证execute(_:)与submit(_:)向事件循环提交任务now与scheduleTask(deadline:in:)基于NIODeadline/TimeAmount的定时任务调度preconditionInEventLoop/preconditionNotInEventLoop调试期断言当前线程身份错误时会按preconditionFailure语义终止进程executor/enqueue将事件循环桥接为 Swift 并发actor 隔离的SerialExecutor。SwiftNIO 当前提供一个EventLoopGroup实现、两个EventLoop实现MultiThreadedEventLoopGroup生产环境位于 Sources/NIOPosix/MultiThreadedEventLoopGroup.swift#L62。它会创建指定数量的线程使用 POSIXpthreads每个线程上放置一个SelectableEventLoop这些线程在调用shutdownGracefully或syncShutdownGracefully之前不会退出。README 特别提醒单元测试常常为每个测试创建一个独立的 group 以强制隔离此时应在setUp中创建、在tearDown中关闭。SelectableEventLoop位于 Sources/NIOPosix/SelectableEventLoop.swift#L94使用 selector在 macOS 上为kqueue、Linux 上为epoll另有 Windows 的 WSA Poll 与 Linux 的 io_uring 支持管理文件描述符的 I/O 事件并分发工作。两者均由NIOPosix提供。EmbeddedEventLoop由NIOEmbedded提供的虚拟事件循环主要用于测试。EventLoop最重要的属性是它是一切工作的执行方式。为了保证线程安全任何要在 SwiftNIO 其他对象上做的工作几乎都必须经由某个EventLoop分发。EventLoop几乎拥有 SwiftNIO 应用中的一切其他对象理解其执行模型是写出高性能 SwiftNIO 应用的关键。相关的实现细节与单测可参考 EventLoopTest.swift 与 EmbeddedEventLoopTest.swift。Channel、ChannelHandler、ChannelPipeline 与 ChannelHandlerContext虽然EventLoop对 SwiftNIO 的运作至关重要但大多数用户与它打交道的程度有限——通常只是请它创建EventLoopPromise或调度任务。用户花最多时间打交道的其实是Channel与ChannelHandler。Channel协议定义在 Sources/NIOCore/Channel.swift#L105用户在 SwiftNIO 程序中接触到的几乎每个文件描述符都与唯一一个Channel关联。Channel拥有该文件描述符并负责管理其生命周期同时负责处理该描述符上的入站/出站事件每当事件循环发现与某描述符相关的事件就通知拥有它的Channel。Channel还暴露closeFuture通道关闭后触发、pipeline、localAddress、remoteAddress、parent、isWritable、isActive等关键属性与write、setOption、getOption等操作。ChannelPipeline一串称为ChannelHandler的对象序列按顺序逐个处理Channel上的事件边处理边修改和转换事件——可以理解为一个数据处理流水线。ChannelHandler入站Inbound或出站Outbound处理器或两者兼具。入站处理器处理入站事件从 socket 读数据、socket 关闭、远端发起的其他事件出站处理器处理出站事件写入、连接尝试、本地 socket 关闭。事件方向读事件从流水线前端向后端逐个传递写事件从后端向前端传递。每个 handler 可随时产生入站或出站事件送往相应方向的下一个 handler——于是 handler 可以拆分读、合并写、延迟连接尝试对事件做任意变换。ChannelHandlerContexthandler 通过它追踪自己在流水线中的位置。它持有流水线中前一个与后一个 handler 的引用确保 handler 只要仍在流水线中就能随时发出事件。ChannelHandler被刻意设计为高度可复用的小组件通常只做一个特定的数据变换再以灵活方式组合从而促进代码复用与封装。SwiftNIO 内置了大量开箱即用的 handler如 HTTP 解析。对高性能应用而言应尽量把业务逻辑放在 handler 中以避免上下文切换的开销。SwiftNIO 还内置了几种Channel实现由NIOPosix提供ServerSocketChannel接受入站连接的 socket、SocketChannelTCP 连接、DatagramChannelUDP socket另有NIOEmbedded提供的EmbeddedChannel主要用于测试。关于阻塞的重要提醒ChannelPipeline是线程安全的——这让 handler 可以写得更简单无需自己做同步。但这种线程安全是通过把所有流水线代码都调度到与EventLoop相同的线程上实现的。因此一般规则是handler 绝不能阻塞除非把阻塞代码派发到后台线程。一旦 handler 阻塞挂在该EventLoop下的所有Channel都会在阻塞调用完成前无法前进。如果确实需要以阻塞风格写代码强烈建议在流水线内处理完后把工作派发到其他线程。相关断言与测试可参见 StrictCrashTests.swift。Bootstrap通道创建的流水线化入口虽然可以直接把Channel注册到EventLoop但更高层的抽象通常更有用。NIOPosix目前提供三个Bootstrap源码均位于 Sources/NIOPosix/Bootstrap.swiftServerBootstrapBootstrap.swift#L82启动监听型通道ClientBootstrapBootstrap.swift#L810启动客户端 TCP 通道并支持 Happy Eyeballs 算法进行 TCP 连接尝试DatagramBootstrapBootstrap.swift#L1672启动 UDP 通道。ByteBuffer面向网络场景的高性能字节缓冲SwiftNIO 应用的大部分工作就是搬运字节缓冲。为此NIOCore提供了ByteBuffer定义于 Sources/NIOCore/ByteBuffer-core.swift#L318——一个快速的写时复制copy-on-write字节缓冲是大多数 SwiftNIO 应用的关键构件。ByteBuffer内部由_Storage负责 CoW、_readerIndex、_writerIndex和_slice组成readerIndex与writerIndex之间是可读字节writerIndex之后是可写空间已读的字节则成为可丢弃字节。它提供了多种实用特性并额外提供unsafe模式钩子关闭边界检查以换取性能但代价是可能把应用暴露于内存正确性问题。强烈建议始终使用安全模式。其切片slicing特性支持零拷贝共享底层存储getSlice(at:length:)得到的视图与原 buffer 共享存储。测试用例可参考 ByteBufferTest.swift。Promise 与 Future异步结果的容器与回调链并发代码与同步代码的一大区别是并非所有操作都会立即完成。例如向通道写数据时事件循环可能无法立即把这次写入刷到网络。为此NIOCore提供了EventLoopPromiseT与EventLoopFutureT来管理异步完成的操作EventLoopFuture定义于 Sources/NIOCore/EventLoopFuture.swift#L423。EventLoopFutureT本质上是某个函数返回值的容器该值将在未来某个时刻被填入。每个 future 都有对应的EventLoopPromiseT即结果将被放入的对象promise 成功后future 就被满足fulfilled。轮询 future 显然太低效所以EventLoopFuture提供托管回调你可以把回调链在 future 上结果可用时它们会被执行。future 会精心安排调度确保回调总是在最初创建 promise 的那个事件循环上执行从而减少回调周围的同步需求。一个值得注意的差异是Channel的close所传 promise 与closeFuture的区别传给close的 promise 在通道关闭后、ChannelPipeline完全清理之前就成功因此你可以在流水线被完全清理前对流水线做最后操作若只想等待通道关闭且流水线清理完毕、无需再做动作则等待closeFuture更合适。EventLoopFuture上有多达数十个回调应用函数map、flatMap、whenComplete、and、recover等具体细节可查阅 API 文档。设计哲学专注低层鼓励生态分工SwiftNIO 的定位是网络应用与框架的强力工具但并非所有抽象层次的完美答案。它紧紧聚焦于在低抽象层提供基本 I/O 原语与协议实现把更富表现力但更慢的抽象留给社区构建。其意图是SwiftNIO 成为服务端应用的构建块而不一定是应用直接使用的框架。需要极致网络性能的应用可以选择直接使用 SwiftNIO以降低抽象开销——这类应用应当能以相对较低的维护成本维持极高性能SwiftNIO 也为此提供实用抽象使极高性能网络服务器可以直接构建。核心仓库内只保留少数极其重要的协议实现如 HTTP。其余大多数协议实现被刻意与底层网络栈的发布节奏解耦两者节奏很可能差异很大因此官方积极鼓励社区在树外开发维护协议实现——事实上包括 TLS 与 HTTP/2 绑定在内的一些第一方协议实现就发展于树外。示例项目一分钟跑起来仓库的Sources目录下内置了多个可运行的示例程序chat client / serverNIOChatClient、NIOChatServerecho client / serverNIOEchoClient、NIOEchoServerUDP echo client / serverNIOUDPEchoClient、NIOUDPEchoServerHTTP client / serverNIOHTTP1Client、NIOHTTP1ServerWebSocket client / serverNIOWebSocketClient、NIOWebSocketServer构建并运行它们只需一条命令把TARGET_NAME换成./Sources下的文件夹名swift run TARGET_NAME例如运行 HTTP 服务器swift run NIOHTTP1Server以 NIOEchoServer/main.swift 为例其结构完整展示了核心构件的配合方式定义EchoHandler: ChannelInboundHandler在channelRead中把读到的数据原样context.write(data, promise: nil)写回在channelReadComplete中context.flush()可利用 gathering writes 合并多个待写缓冲出错时打印并关闭用MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)创建按 CPU 核心数分配线程的事件循环组用ServerBootstrap(group:)配置serverChannelOption(.backlog, value: 256)、serverChannelOption(.socketOption(.so_reuseaddr), value: 1)childChannelInitializer中依次加入BackPressureHandler()防止读快于写与EchoHandler()childChannelOption设置so_reuseaddr、maxMessagesPerRead16与AdaptiveRecvByteBufferAllocator()bootstrap.bind(host:port:)后wait()阻塞到绑定完成再channel.closeFuture.wait()保持服务运行。开始使用 SwiftNIOSwiftNIO 主要使用SwiftPM作为构建工具。要在自己的项目中依赖 SwiftNIO只需在Package.swift中加入dependencies子句dependencies: [ .package(url: https://github.com/apple/swift-nio.git, from: 2.0.0) ]然后把相应模块加到 target 依赖中。不同 Swift 版本的目标依赖语法略有差异。例如在swift-tools-version:5.4Swift 5.4 及更新中依赖NIOCore、NIOPosix与NIOHTTP1dependencies: [.product(name: NIOCore, package: swift-nio), .product(name: NIOPosix, package: swift-nio), .product(name: NIOHTTP1, package: swift-nio)]使用 Xcode 的包支持若项目是 Xcode 工程且使用 Xcode 11可通过 File - Swift Packages - Add Package Dependency 添加 SwiftNIO 依赖在对话框中输入https://github.com/apple/swift-nio.git点 Next 两次最后勾选要使用的 target如NIOCore、NIOHTTP1、NIOFoundationCompat并完成。之后即可在项目里import NIOCore以及勾选的其他 target。克隆仓库本地构建若要开发 SwiftNIO 本身或研究演示应用可直接克隆仓库并用 SwiftPM 构建。例如编译、测试并运行 echo 服务器swift build swift test swift run NIOEchoServer验证它是否工作另开一个 shell 尝试连接echo 服务器默认监听::1:9999echo Hello SwiftNIO | nc localhost 9999一切正常的话你会看到这条消息被原样回显。若要在 Xcode 中开发 SwiftNIO直接打开Package.swift文件使用 Xcode 对 SwiftPM 包的支持即可。开发 SwiftNIO 的前置条件注本节仅适用于想亲自开发 SwiftNIO 的人如果只是把它当作 SwiftPM 包使用可以忽略。SwiftNIO 的main分支是 SwiftNIO 2 下一版本的开发分支仅支持 Swift 5。要编译运行 SwiftNIO 与集成测试需要安装若干前置条件macOSXcode 11.4 或更新推荐 Xcode 12。Linux来自 swift.org/download 的 Swift 5.7 或更新始终推荐最新发布版netcat仅集成测试、lsof仅集成测试、shasum仅集成测试。Ubuntu 18.04安装 swift tarball 后执行apt-get install -y git curl libatomic1 libxml2 netcat-openbsd lsof perlFedora 28dnf install swift-lang /usr/bin/nc /usr/bin/lsof /usr/bin/shasum整体而言SwiftNIO 的开发与任何其他 SwiftPM 项目一样直接在贡献前建议阅读仓库内的 CONTRIBUTING.md 了解流程细节。仓库的集成测试位于 IntegrationTests 目录涵盖了 HTTP 场景、系统调用包装器、调试二进制检查、分配计数性能测试等大量回归用例是理解框架行为边界的宝贵资料。赞分享后端网络【免费下载链接】swift-nioEvent-driven network application framework for high performance protocol servers clients, non-blocking.项目地址https://gitcode.com/gh_mirrors/sw/swift-nio点击查看免费下载相关推荐SwiftNIO 架构解析事件驱动、非阻塞的高性能网络框架核心模块与编程模型SwiftNIO 架构解析事件驱动、非阻塞的高性能网络框架核心模块与编程模型 SwiftNIO 是一个跨平台的异步事件驱动网络应用框架目标是帮助开发者快速构后端网络深入理解HAProxy架构事件驱动与非阻塞I/O模型解析深入理解HAProxy架构事件驱动与非阻塞I/O模型解析 HAProxy作为业界领先的高性能负载均衡器其核心优势在于精心设计的事件驱动架构和非阻塞I/O模型负载均衡反向代理后端API网关高可用网络终极指南Mongoose事件驱动架构解析与非阻塞IO核心机制终极指南Mongoose事件驱动架构解析与非阻塞IO核心机制 Mongoose是一个为C/C设计的网络库它提供了事件驱动的非阻塞IO模型让开发者能够轻嵌入式网络通信物联网上一篇C-RADIOv4-SO400M部署教程从本地到云端完整指南下一篇LOSEHU系列固件解锁UV-K5/K6无线电设备的无限潜能创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表