Socket(套接字) 是应用层与 TCP/IP 协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket 其实就是一个门面模式,它把复杂的 TCP/IP 协议族隐藏在 Socket 接口后面。
对开发者来说,Socket 就是 “IP 地址 + 协议 + 端口” 的结合体,通过它,你的 App 才能在互联网上精准地找到另一台设备并交换数据。
1. TCP Socket vs UDP Socket
在 iOS 中,选择哪种 Socket 取决于你的业务需求:
| 特性 | TCP Socket (流式) | UDP Socket (数据报) |
|---|---|---|
| 连接性 | 面向连接(三次握手) | 无连接 |
| 可靠性 | 保证交付、顺序一致、无差错 | 不保证交付,可能丢包或乱序 |
| 数据边界 | 字节流(存在“粘包”问题) | 保留数据边界(发多大收多大) |
| 适用场景 | 即时通讯(IM)、文件传输、远程登录 | 实时音视频、在线游戏、局域网发现 |
2. 在 iOS 中如何使用 (现代方式)
虽然 iOS 依然支持传统的 C 语言 BSD Sockets,但 Apple 强烈建议使用 Network.framework (iOS 12+)。它不仅支持 Swift,还能自动处理 Wi-Fi/蜂窝网切换、低功耗优化等。
A. 使用 TCP Socket
TCP 需要先建立连接,然后才能进行双向数据流传输。
Swift
import Network
// 1. 创建连接 (指定 Host 和 Port)
let connection = NWConnection(host: "192.168.1.100", port: 8080, using: .tcp)
// 2. 监听连接状态
connection.stateUpdateHandler = { state in
switch state {
case .ready:
print("TCP 连接已就绪")
// 连接成功后可以发送数据
case .failed(let error):
print("连接失败: (error)")
default: break
}
}
// 3. 启动连接
connection.start(queue: .main)
// 4. 发送数据
let content = "Hello Server".data(using: .utf8)
connection.send(content: content, completion: .contentProcessed({ error in
if let error = error { print("发送失败: (error)") }
}))
// 5. 接收数据
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { data, _, isComplete, _ in
if let data = data, !data.isEmpty {
print("收到回复: (String(data: data, encoding: .utf8) ?? "")")
}
}
B. 使用 UDP Socket
UDP 不需要握手,直接通过 NWConnection 发送数据包。
Swift
// 1. 使用 .udp 协议
let udpConnection = NWConnection(host: "255.255.255.255", port: 9000, using: .udp)
// 2. 配置允许广播 (如果是局域网发现)
let params = NWParameters.udp
params.allowLocalEndpointReuse = true
// 注意:UDP 通常用于快速发送小数据包
// 3. 发送数据 (无需等待连接确认,直接尝试发送)
udpConnection.start(queue: .main)
let packet = "Discovery_Signal".data(using: .utf8)
udpConnection.send(content: packet, completion: .idempotent)
3. iOS 开发中的关键点
- 后台存活:标准的 Socket 连接在 App 进入后台后会被系统挂起或切断。如果需要长连接(如 IM),通常建议使用 Apple 推送 (APNs) 唤醒,或申请特定的后台运行权限。
- 粘包问题 (TCP) :TCP 是基于流的,如果你连发两条消息
"Hello"和"World",接收方可能一次性收到"HelloWorld"。你需要自己定义数据包协议(例如在包头加 4 字节的长度字段)。 - Local Network 权限:在 iOS 14+ 中,如果你的 Socket 是连接局域网设备,必须在
Info.plist中配置NSLocalNetworkUsageDescription,否则连接会静默失败。 - 性能优化:尽量复用
NWConnection对象,频繁创建/销毁 Socket 会非常耗电。
总结
- TCP 用于需要“稳”的场景,它是 iOS 中长连接(IM、控制协议)的首选。
- UDP 用于需要“快”或“广播”的场景。
- Network.framework 是目前 iOS 开发 Socket 的最佳实践。