防丢包需要根据不同的协议和场景采用不同的策略。让我为你详细介绍各种防丢包方案:
一、TCP 层面的防丢包(自动处理)
TCP 本身已经内置了完善的防丢包机制:
1. TCP 自动重传机制
swift
// TCP 自动处理丢包,开发者无需关心
class TCPConnection {
func sendData(_ data: Data) {
// TCP 底层自动处理:
// ✅ 序列号:检测丢失和乱序
// ✅ 确认机制:接收方确认收到
// ✅ 超时重传:未确认的数据自动重发
// ✅ 快速重传:收到3个重复ACK立即重传
outputStream.write(data: data)
}
}
2. TCP 参数优化
swift
import Darwin
class OptimizedTCP {
func optimizeSocket(_ socket: Int32) {
// 1. 启用TCP_NODELAY(禁用Nagle算法)
var noDelay: Int32 = 1
setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, &noDelay, socklen_t(MemoryLayout<Int32>.size))
// 2. 调整缓冲区大小
var sendBufferSize = 1024 * 64 // 64KB
var recvBufferSize = 1024 * 64
setsockopt(socket, SOL_SOCKET, SO_SNDBUF, &sendBufferSize, socklen_t(MemoryLayout<Int32>.size))
setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &recvBufferSize, socklen_t(MemoryLayout<Int32>.size))
// 3. 启用KeepAlive
var keepAlive: Int32 = 1
setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, socklen_t(MemoryLayout<Int32>.size))
}
}
二、UDP 层面的防丢包(需要手动实现)
UDP本身不保证可靠性,需要应用层实现防丢包:
1. 基础确认重传机制
swift
class ReliableUDP {
private var sequenceNumber: UInt32 = 0
private var pendingPackets: [UInt32: (data: Data, timestamp: Date, retries: Int)] = [:]
private let maxRetries = 3
private let ackTimeout: TimeInterval = 1.0
struct PacketHeader {
let sequence: UInt32
let totalParts: UInt16
let partNumber: UInt16
let checksum: UInt32
}
func sendReliableData(_ data: Data) {
let sequence = sequenceNumber
sequenceNumber += 1
let packets = splitIntoPackets(data, sequence: sequence)
for packet in packets {
sendPacket(packet, sequence: sequence)
}
}
private func sendPacket(_ packet: Data, sequence: UInt32) {
pendingPackets[sequence] = (
data: packet,
timestamp: Date(),
retries: 0
)
udpSend(packet)
startAckTimer(for: sequence)
}
private func startAckTimer(for sequence: UInt32) {
DispatchQueue.main.asyncAfter(deadline: .now() + ackTimeout) { [weak self] in
guard let self = self,
var pending = self.pendingPackets[sequence],
Date().timeIntervalSince(pending.timestamp) >= self.ackTimeout else {
return
}
if pending.retries < self.maxRetries {
pending.retries += 1
pending.timestamp = Date()
self.pendingPackets[sequence] = pending
print("🔁 重传序列 \(sequence),尝试 \(pending.retries)/\(self.maxRetries)")
self.udpSend(pending.data)
self.startAckTimer(for: sequence)
} else {
print("❌ 序列 \(sequence) 重传失败")
self.pendingPackets.removeValue(forKey: sequence)
self.handlePacketLoss(sequence)
}
}
}
func receiveAck(_ sequence: UInt32) {
if pendingPackets.removeValue(forKey: sequence) != nil {
print("✅ 确认序列 \(sequence)")
}
}
}
2. 选择性重传(SACK)
swift
class SelectiveRetransmissionUDP {
private var receivedSequences = Set<UInt32>()
func receivePacket(_ packet: Data) -> (needAck: Bool, missingSequences: [UInt32]) {
let header = parseHeader(packet)
// 记录已收到的序列号
receivedSequences.insert(header.sequence)
// 检查是否有缺失的包
let missing = findMissingSequences()
// 如果需要确认或报告缺失
let needAck = shouldSendAck()
return (needAck, missing)
}
private func findMissingSequences() -> [UInt32] {
guard let maxSeq = receivedSequences.max() else { return [] }
var missing: [UInt32] = []
for seq in 0...maxSeq {
if !receivedSequences.contains(seq) {
missing.append(seq)
}
}
return missing
}
}
三、应用层防丢包策略
1. 消息确认机制
swift
class MessageAckManager {
private var pendingMessages: [String: (message: Any, timestamp: Date)] = [:]
private let ackTimeout: TimeInterval = 5.0
func sendMessageWithAck(_ message: ControlMessage, to device: String) {
let messageId = UUID().uuidString
let messageWithId = IdentifiedMessage(id: messageId, content: message)
pendingMessages[messageId] = (message: message, timestamp: Date())
// 发送消息
sendToDevice(messageWithId, device: device)
// 启动确认计时器
startAckTimer(for: messageId)
}
func handleAck(_ messageId: String) {
if pendingMessages.removeValue(forKey: messageId) != nil {
print("✅ 消息 \(messageId) 确认收到")
}
}
private func startAckTimer(for messageId: String) {
DispatchQueue.main.asyncAfter(deadline: .now() + ackTimeout) { [weak self] in
guard let self = self,
let pending = self.pendingMessages[messageId] else {
return
}
if Date().timeIntervalSince(pending.timestamp) >= self.ackTimeout {
print("🔄 消息 \(messageId) 超时,重新发送")
self.resendMessage(messageId)
}
}
}
}
2. 数据分片和重组
swift
class FragmentationManager {
private var reassemblyBuffers: [UInt32: [Int: Data]] = [:]
private let maxFragmentSize = 1024 // 1KB
func splitAndSend(_ largeData: Data, sequence: UInt32) {
let totalFragments = (largeData.count + maxFragmentSize - 1) / maxFragmentSize
for fragmentIndex in 0..<totalFragments {
let start = fragmentIndex * maxFragmentSize
let end = min(start + maxFragmentSize, largeData.count)
let fragment = largeData.subdata(in: start..<end)
let fragmentHeader = FragmentHeader(
sequence: sequence,
totalFragments: UInt16(totalFragments),
fragmentIndex: UInt16(fragmentIndex)
)
sendFragment(fragment, header: fragmentHeader)
}
}
func receiveFragment(_ fragment: Data, header: FragmentHeader) -> Data? {
let sequence = header.sequence
// 初始化重组缓冲区
if reassemblyBuffers[sequence] == nil {
reassemblyBuffers[sequence] = [:]
}
// 存储分片
reassemblyBuffers[sequence]?[Int(header.fragmentIndex)] = fragment
// 检查是否收齐所有分片
if let buffer = reassemblyBuffers[sequence],
buffer.count == Int(header.totalFragments) {
// 按顺序重组数据
var reassembledData = Data()
for i in 0..<Int(header.totalFragments) {
if let fragmentData = buffer[i] {
reassembledData.append(fragmentData)
}
}
reassemblyBuffers.removeValue(forKey: sequence)
return reassembledData
}
return nil
}
}
四、MQTT 的防丢包(QoS机制)
1. MQTT QoS 等级
swift
class MQTTQualityOfService {
func demonstrateQoSLevels() {
let mqttClient = CocoaMQTT(clientID: "device123")
// QoS 0: 最多一次(可能丢失)
mqttClient.publish("sensors/temp", withString: "25", qos: .qos0)
// QoS 1: 至少一次(可能重复)
mqttClient.publish("commands/light", withString: "on", qos: .qos1)
// QoS 2: 恰好一次(可靠)
mqttClient.publish("config/update", withString: configJson, qos: .qos2)
}
}
// QoS 1 实现示例
class QoS1Handler {
private var pendingPubAck: [UInt16: (message: Data, timestamp: Date)] = [:]
func publishWithQoS1(_ message: String, topic: String) -> UInt16 {
let messageId = generateMessageId()
let mqttMessage = CocoaMQTTMessage(topic: topic, string: message, qos: .qos1)
mqttMessage.messageId = messageId
// 存储等待确认
pendingPubAck[messageId] = (
message: message.data(using: .utf8)!,
timestamp: Date()
)
mqttClient.publish(mqttMessage)
startPubAckTimer(messageId: messageId)
return messageId
}
func handlePubAck(_ messageId: UInt16) {
if pendingPubAck.removeValue(forKey: messageId) != nil {
print("✅ QoS1 消息 \(messageId) 确认")
}
}
}
五、WebSocket 的防丢包
1. 应用层心跳和重连
swift
class ReliableWebSocket: WebSocketDelegate {
private var heartbeatTimer: Timer?
private var reconnectTimer: Timer?
private var isConnected = false
private let heartbeatInterval: TimeInterval = 30.0
func setupHeartbeat() {
heartbeatTimer = Timer.scheduledTimer(withTimeInterval: heartbeatInterval, repeats: true) { [weak self] _ in
self?.sendHeartbeat()
}
}
private func sendHeartbeat() {
let heartbeatMessage = ["type": "heartbeat", "timestamp": Date().timeIntervalSince1970]
if let data = try? JSONSerialization.data(withJSONObject: heartbeatMessage) {
webSocket.write(data: data)
}
}
func handleDisconnection() {
isConnected = false
scheduleReconnect()
}
private func scheduleReconnect() {
reconnectTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { [weak self] _ in
self?.webSocket.connect()
}
}
}
2. 消息确认机制
swift
class WebSocketAckManager {
private var pendingAcks: [String: (message: Any, callback: (Bool) -> Void)] = [:]
private let ackTimeout: TimeInterval = 10.0
func sendMessageWithAck(_ message: [String: Any], completion: @escaping (Bool) -> Void) {
let messageId = UUID().uuidString
var messageWithId = message
messageWithId["id"] = messageId
messageWithId["needAck"] = true
if let data = try? JSONSerialization.data(withJSONObject: messageWithId) {
pendingAcks[messageId] = (message: message, callback: completion)
webSocket.write(data: data)
// 设置超时
DispatchQueue.main.asyncAfter(deadline: .now() + ackTimeout) { [weak self] in
if let callback = self?.pendingAcks[messageId]?.callback {
callback(false) // 超时失败
self?.pendingAcks.removeValue(forKey: messageId)
}
}
}
}
func handleAck(_ messageId: String) {
if let (_, callback) = pendingAcks.removeValue(forKey: messageId) {
callback(true) // 成功确认
}
}
}
六、网络质量自适应策略
1. 动态调整策略
swift
class AdaptiveTransmission {
private var packetLossRate: Double = 0.0
private var rtt: TimeInterval = 0.1 // 初始RTT
private let samplingWindow = 100 // 采样窗口
func updateNetworkMetrics(sent: Int, lost: Int, newRtt: TimeInterval) {
// 更新丢包率
packetLossRate = Double(lost) / Double(sent)
// 更新RTT(指数加权移动平均)
rtt = 0.875 * rtt + 0.125 * newRtt
adjustTransmissionStrategy()
}
private func adjustTransmissionStrategy() {
if packetLossRate > 0.1 {
// 高丢包率:减少数据量,增加重试
reduceDataRate()
increaseRetryCount()
} else if rtt > 1.0 {
// 高延迟:使用压缩,减少交互次数
enableCompression()
batchMessages()
} else {
// 网络良好:正常传输
useNormalStrategy()
}
}
private func reduceDataRate() {
// 降低发送频率,减少数据大小
print("📉 网络质量差,降低传输速率")
}
}
七、综合防丢包方案
混合策略管理器
swift
class AntiPacketLossManager {
private let networkMonitor = NetworkMonitor()
private let retryManager = RetryManager()
private let fragmentationManager = FragmentationManager()
func sendDataReliably(_ data: Data, to destination: String) {
let networkCondition = networkMonitor.currentCondition
switch networkCondition {
case .excellent:
// 网络好:直接发送
sendDirectly(data, to: destination)
case .good:
// 网络一般:添加确认机制
sendWithAck(data, to: destination)
case .poor where data.count > 1024:
// 网络差且数据大:分片发送
fragmentationManager.splitAndSend(data, to: destination)
case .poor:
// 网络差:增加重试次数
sendWithRetry(data, to: destination, maxRetries: 5)
case .unstable:
// 网络不稳定:使用最可靠的方案
sendWithFragmentationAndAck(data, to: destination)
}
}
private func sendWithFragmentationAndAck(_ data: Data, to destination: String) {
print("🛡️ 使用分片+确认机制发送数据")
// 组合使用分片和确认机制
}
}
总结
防丢包策略选择:
场景 | 推荐策略 | 具体措施 |
---|---|---|
TCP通信 | 依赖TCP机制 | 调整缓冲区、启用KeepAlive |
UDP通信 | 应用层实现 | 序列号、确认、重传、分片 |
MQTT | 使用QoS | QoS1/QoS2、持久会话 |
WebSocket | 应用层确认 | 心跳、消息ID、重连 |
大文件传输 | 分片传输 | 数据分片、选择性重传 |
实时数据 | 前向纠错 | 添加冗余数据 |
关键原则:
- TCP优先:能用TCP就不要用UDP
- 分层防护:传输层+应用层双重保障
- 自适应:根据网络状况动态调整策略
- 监控反馈:实时监控丢包率并调整参数
根据你的具体应用场景选择合适的防丢包组合策略。