axiom-networking-legacy by charleswiltgen/axiom
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-networking-legacy这些模式使用带完成处理程序的 NWConnection,适用于支持 iOS 12-25 的应用。如果你的应用目标为 iOS 26+,请改用带 async/await 的 NetworkConnection(参见 axiom-network-framework-ref 技能)。
适用场景 支持 iOS 12-25,需要 TLS 加密,尚不能使用 async/await
耗时 10-15 分钟
import Network
// 创建带 TLS 的连接
let connection = NWConnection(
host: NWEndpoint.Host("mail.example.com"),
port: NWEndpoint.Port(integerLiteral: 993),
using: .tls // 推断为 TCP
)
// 处理连接状态变化
connection.stateUpdateHandler = { [weak self] state in
switch state {
case .ready:
print("连接已建立")
self?.sendInitialData()
case .waiting(let error):
print("等待网络:\(error)")
// 显示"等待中..." UI,不要立即失败
case .failed(let error):
print("连接失败:\(error)")
case .cancelled:
print("连接已取消")
default:
break
}
}
// 启动连接
connection.start(queue: .main)
// 带节奏控制的数据发送
func sendData() {
let data = Data("Hello, world!".utf8)
connection.send(content: data, completion: .contentProcessed { [weak self] error in
if let error = error {
print("发送错误:\(error)")
return
}
// contentProcessed 回调 = 网络栈已消费数据
// 此时应发送下一个数据块(节奏控制)
self?.sendNextChunk()
})
}
// 接收精确字节数
func receiveData() {
connection.receive(minimumIncompleteLength: 10, maximumLength: 10) { [weak self] (data, context, isComplete, error) in
if let error = error {
print("接收错误:\(error)")
return
}
if let data = data {
print("收到 \(data.count) 字节")
// 处理数据...
self?.receiveData() // 继续接收
}
}
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
[weak self] 以防止循环引用适用场景 支持 iOS 12-25,高效发送多个 UDP 数据报,需要降低约 30% 的 CPU 使用率
耗时 10-15 分钟
背景 传统 UDP 套接字每个系统调用发送一个数据报。如果你要发送 100 个小数据包,那就是 100 次上下文切换。批量发送可将其减少到约 1 个系统调用。
// 错误 — 100 个数据包需要 100 次上下文切换
for frame in videoFrames {
sendto(socket, frame.bytes, frame.count, 0, &addr, addrlen)
// 每次发送 = 切换到内核的上下文切换
}
import Network
// UDP 连接
let connection = NWConnection(
host: NWEndpoint.Host("stream-server.example.com"),
port: NWEndpoint.Port(integerLiteral: 9000),
using: .udp
)
connection.stateUpdateHandler = { state in
if case .ready = state {
print("准备发送 UDP")
}
}
connection.start(queue: .main)
// 批量发送以提高效率
func sendVideoFrames(_ frames: [Data]) {
connection.batch {
for frame in frames {
connection.send(content: frame, completion: .contentProcessed { error in
if let error = error {
print("发送错误:\(error)")
}
})
}
}
// 所有发送批量合并为约 1 个系统调用
// 相比单独发送降低 30% CPU 使用率
}
// 接收 UDP 数据报
func receiveFrames() {
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { [weak self] (data, context, isComplete, error) in
if let error = error {
print("接收错误:\(error)")
return
}
if let data = data {
// 处理视频帧
self?.displayFrame(data)
self?.receiveFrames() // 继续接收
}
}
}
WWDC 2018 演示 实时视频流显示,使用用户空间网络 + 批量发送时,接收端 CPU 降低 30%
适用场景 需要接受传入连接,构建服务器或点对点应用,支持 iOS 12-25
耗时 20-25 分钟
// 错误 — 手动套接字管理
let sock = socket(AF_INET, SOCK_STREAM, 0)
bind(sock, &addr, addrlen)
listen(sock, 5)
while true {
let client = accept(sock, nil, nil) // 阻塞线程
// 处理客户端...
}
import Network
// 使用默认参数创建监听器
let listener = try NWListener(using: .tcp, on: 1029)
// 广告 Bonjour 服务
listener.service = NWListener.Service(name: "MyApp", type: "_myservice._tcp")
// 处理服务注册更新
listener.serviceRegistrationUpdateHandler = { update in
switch update {
case .add(let endpoint):
if case .service(let name, let type, let domain, _) = endpoint {
print("广告为:\(name).\(type)\(domain)")
}
default:
break
}
}
// 处理传入连接
listener.newConnectionHandler = { [weak self] newConnection in
print("新连接来自:\(newConnection.endpoint)")
// 配置连接
newConnection.stateUpdateHandler = { state in
switch state {
case .ready:
print("客户端已连接")
self?.handleClient(newConnection)
case .failed(let error):
print("客户端连接失败:\(error)")
default:
break
}
}
// 开始处理此连接
newConnection.start(queue: .main)
}
// 处理监听器状态
listener.stateUpdateHandler = { state in
switch state {
case .ready:
print("监听器在端口 \(listener.port ?? 0) 上就绪")
case .failed(let error):
print("监听器失败:\(error)")
default:
break
}
}
// 开始监听
listener.start(queue: .main)
// 处理客户端数据
func handleClient(_ connection: NWConnection) {
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { [weak self] (data, context, isComplete, error) in
if let error = error {
print("接收错误:\(error)")
return
}
if let data = data {
print("收到 \(data.count) 字节")
// 回显
connection.send(content: data, completion: .contentProcessed { error in
if let error = error {
print("发送错误:\(error)")
}
})
self?.handleClient(connection) // 继续接收
}
}
}
NWListener(using: .tls, on: port)适用场景 在本地网络上发现服务(Bonjour),构建点对点应用,支持 iOS 12-25
耗时 25-30 分钟
// 错误 — 脆弱,需要手动配置
let connection = NWConnection(host: "192.168.1.100", port: 9000, using: .tcp)
// 如果 IP 变了怎么办?如果有多个设备怎么办?
import Network
// 在本地网络上浏览服务
let browser = NWBrowser(for: .bonjour(type: "_myservice._tcp", domain: nil), using: .tcp)
// 处理发现的服务
browser.browseResultsChangedHandler = { results, changes in
for result in results {
switch result.endpoint {
case .service(let name, let type, let domain, _):
print("发现服务:\(name).\(type)\(domain)")
// 连接到此服务
self.connectToService(result.endpoint)
default:
break
}
}
}
// 处理浏览器状态
browser.stateUpdateHandler = { state in
switch state {
case .ready:
print("浏览器就绪")
case .failed(let error):
print("浏览器失败:\(error)")
default:
break
}
}
// 开始浏览
browser.start(queue: .main)
// 连接到发现的服务
func connectToService(_ endpoint: NWEndpoint) {
let connection = NWConnection(to: endpoint, using: .tcp)
connection.stateUpdateHandler = { state in
if case .ready = state {
print("已连接到服务")
}
}
connection.start(queue: .main)
}
技能 : axiom-networking, axiom-network-framework-ref, axiom-networking-migration
每周安装量
90
代码仓库
GitHub 星标数
606
首次出现
2026年1月21日
安全审计
安装于
opencode75
claude-code71
codex70
gemini-cli68
cursor67
github-copilot65
These patterns use NWConnection with completion handlers for apps supporting iOS 12-25. If your app targets iOS 26+, use NetworkConnection with async/await instead (see axiom-network-framework-ref skill).
Use when Supporting iOS 12-25, need TLS encryption, can't use async/await yet
Time cost 10-15 minutes
import Network
// Create connection with TLS
let connection = NWConnection(
host: NWEndpoint.Host("mail.example.com"),
port: NWEndpoint.Port(integerLiteral: 993),
using: .tls // TCP inferred
)
// Handle connection state changes
connection.stateUpdateHandler = { [weak self] state in
switch state {
case .ready:
print("Connection established")
self?.sendInitialData()
case .waiting(let error):
print("Waiting for network: \(error)")
// Show "Waiting..." UI, don't fail immediately
case .failed(let error):
print("Connection failed: \(error)")
case .cancelled:
print("Connection cancelled")
default:
break
}
}
// Start connection
connection.start(queue: .main)
// Send data with pacing
func sendData() {
let data = Data("Hello, world!".utf8)
connection.send(content: data, completion: .contentProcessed { [weak self] error in
if let error = error {
print("Send error: \(error)")
return
}
// contentProcessed callback = network stack consumed data
// This is when you should send next chunk (pacing)
self?.sendNextChunk()
})
}
// Receive exact byte count
func receiveData() {
connection.receive(minimumIncompleteLength: 10, maximumLength: 10) { [weak self] (data, context, isComplete, error) in
if let error = error {
print("Receive error: \(error)")
return
}
if let data = data {
print("Received \(data.count) bytes")
// Process data...
self?.receiveData() // Continue receiving
}
}
}
[weak self] in all completion handlers to prevent retain cyclesUse when Supporting iOS 12-25, sending multiple UDP datagrams efficiently, need ~30% CPU reduction
Time cost 10-15 minutes
Background Traditional UDP sockets send one datagram per syscall. If you're sending 100 small packets, that's 100 context switches. Batching reduces this to ~1 syscall.
// WRONG — 100 context switches for 100 packets
for frame in videoFrames {
sendto(socket, frame.bytes, frame.count, 0, &addr, addrlen)
// Each send = context switch to kernel
}
import Network
// UDP connection
let connection = NWConnection(
host: NWEndpoint.Host("stream-server.example.com"),
port: NWEndpoint.Port(integerLiteral: 9000),
using: .udp
)
connection.stateUpdateHandler = { state in
if case .ready = state {
print("Ready to send UDP")
}
}
connection.start(queue: .main)
// Batch sending for efficiency
func sendVideoFrames(_ frames: [Data]) {
connection.batch {
for frame in frames {
connection.send(content: frame, completion: .contentProcessed { error in
if let error = error {
print("Send error: \(error)")
}
})
}
}
// All sends batched into ~1 syscall
// 30% lower CPU usage vs individual sends
}
// Receive UDP datagrams
func receiveFrames() {
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { [weak self] (data, context, isComplete, error) in
if let error = error {
print("Receive error: \(error)")
return
}
if let data = data {
// Process video frame
self?.displayFrame(data)
self?.receiveFrames() // Continue receiving
}
}
}
WWDC 2018 demo Live video streaming showed 30% lower CPU on receiver with user-space networking + batching
Use when Need to accept incoming connections, building servers or peer-to-peer apps, supporting iOS 12-25
Time cost 20-25 minutes
// WRONG — Manual socket management
let sock = socket(AF_INET, SOCK_STREAM, 0)
bind(sock, &addr, addrlen)
listen(sock, 5)
while true {
let client = accept(sock, nil, nil) // Blocks thread
// Handle client...
}
import Network
// Create listener with default parameters
let listener = try NWListener(using: .tcp, on: 1029)
// Advertise Bonjour service
listener.service = NWListener.Service(name: "MyApp", type: "_myservice._tcp")
// Handle service registration updates
listener.serviceRegistrationUpdateHandler = { update in
switch update {
case .add(let endpoint):
if case .service(let name, let type, let domain, _) = endpoint {
print("Advertising as: \(name).\(type)\(domain)")
}
default:
break
}
}
// Handle incoming connections
listener.newConnectionHandler = { [weak self] newConnection in
print("New connection from: \(newConnection.endpoint)")
// Configure connection
newConnection.stateUpdateHandler = { state in
switch state {
case .ready:
print("Client connected")
self?.handleClient(newConnection)
case .failed(let error):
print("Client connection failed: \(error)")
default:
break
}
}
// Start handling this connection
newConnection.start(queue: .main)
}
// Handle listener state
listener.stateUpdateHandler = { state in
switch state {
case .ready:
print("Listener ready on port \(listener.port ?? 0)")
case .failed(let error):
print("Listener failed: \(error)")
default:
break
}
}
// Start listening
listener.start(queue: .main)
// Handle client data
func handleClient(_ connection: NWConnection) {
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { [weak self] (data, context, isComplete, error) in
if let error = error {
print("Receive error: \(error)")
return
}
if let data = data {
print("Received \(data.count) bytes")
// Echo back
connection.send(content: data, completion: .contentProcessed { error in
if let error = error {
print("Send error: \(error)")
}
})
self?.handleClient(connection) // Continue receiving
}
}
}
NWListener(using: .tls, on: port)Use when Discovering services on local network (Bonjour), building peer-to-peer apps, supporting iOS 12-25
Time cost 25-30 minutes
// WRONG — Brittle, requires manual configuration
let connection = NWConnection(host: "192.168.1.100", port: 9000, using: .tcp)
// What if IP changes? What if multiple devices?
import Network
// Browse for services on local network
let browser = NWBrowser(for: .bonjour(type: "_myservice._tcp", domain: nil), using: .tcp)
// Handle discovered services
browser.browseResultsChangedHandler = { results, changes in
for result in results {
switch result.endpoint {
case .service(let name, let type, let domain, _):
print("Found service: \(name).\(type)\(domain)")
// Connect to this service
self.connectToService(result.endpoint)
default:
break
}
}
}
// Handle browser state
browser.stateUpdateHandler = { state in
switch state {
case .ready:
print("Browser ready")
case .failed(let error):
print("Browser failed: \(error)")
default:
break
}
}
// Start browsing
browser.start(queue: .main)
// Connect to discovered service
func connectToService(_ endpoint: NWEndpoint) {
let connection = NWConnection(to: endpoint, using: .tcp)
connection.stateUpdateHandler = { state in
if case .ready = state {
print("Connected to service")
}
}
connection.start(queue: .main)
}
Skills : axiom-networking, axiom-network-framework-ref, axiom-networking-migration
Weekly Installs
90
Repository
GitHub Stars
606
First Seen
Jan 21, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
opencode75
claude-code71
codex70
gemini-cli68
cursor67
github-copilot65
Swift Actor 线程安全持久化:构建离线优先应用的编译器强制安全数据层
1,700 周安装
pytest-coverage:Python测试覆盖率工具,一键生成代码覆盖率报告
8,300 周安装
Markdown转HTML专业技能 - 使用marked.js、Pandoc和Hugo实现高效文档转换
8,200 周安装
GitHub Copilot 技能模板制作指南 - 创建自定义 Agent Skills 分步教程
8,200 周安装
ImageMagick图像处理技能:批量调整大小、格式转换与元数据提取
8,200 周安装
GitHub Actions 工作流规范创建指南:AI优化模板与CI/CD流程设计
8,200 周安装
GitHub Copilot SDK 官方开发包 - 在应用中嵌入AI智能体工作流(Python/TypeScript/Go/.NET)
8,200 周安装