不同的通信协议

209 阅读20分钟

协议对比矩阵

特性TCPUDPWebSocketMQTT
可靠性🥇 自动重传❌ 无保障✅ 基于TCP保障✅ 可配置(QoS)
延迟✅ 低🥇 最低✅ 低(全双工)✅ 低
带宽开销✅ 中等🥇 最小❌ 较高(协议头)❌ 较高
连接管理🥇 自动✅ 无连接✅ 持久连接🥇 自动
数据顺序🥇 保证❌ 不保证✅ 保证✅ 保证
实现复杂度✅ 中等✅ 简单✅ 简单(有库)✅ 简单
防火墙穿透❌ 困难✅ 容易✅ 容易(HTTP端口)✅ 容易
适用场景可靠控制实时数据实时双向通信消息队列

一、协议分层对比

协议OSI分层TCP/IP分层本质
TCP传输层(4)传输层面向连接的可靠字节流协议
UDP传输层(4)传输层无连接的不可靠数据报协议
WebSocket应用层(7)应用层基于TCP的全双工通信协议
MQTT应用层(7)应用层基于TCP的发布订阅消息协议

二、底层逻辑详解

1. TCP (传输控制协议)

底层逻辑:建立虚拟电路,保证数据可靠传输

// TCP 的三次握手建立连接
Client  Server: SYN (我要连接)
Client  Server: SYN-ACK (我准备好了)  
Client  Server: ACK (开始通信)

// 数据传输保证
- 序列号:保证数据顺序
- 确认机制:收到数据要确认
- 重传机制:丢失数据自动重发
- 流量控制:防止发送过快
- 拥塞控制:防止网络拥堵

核心特点

  • 🔗 面向连接:需要先建立连接
  • 可靠传输:数据不丢失、不重复、按序到达
  • 📦 字节流:没有消息边界,是连续的字节流
  • 🐢 速度较慢:有各种控制机制

2. UDP (用户数据报协议)

底层逻辑:直接发送数据包,不保证可靠性

// UDP 的无连接通信
Client  Server: 数据包1
Client  Server: 数据包2
Client  Server: 数据包3  // 可能丢失
// 没有确认、没有重传、没有顺序保证

核心特点

  • 🎯 无连接:直接发送,无需建立连接
  • 速度快:没有控制开销
  • 不可靠:可能丢失、重复、乱序
  • 📨 数据报:有消息边界,每个包独立
  • 📢 支持广播:可向多个目标发送

3. WebSocket

底层逻辑:在TCP之上建立全双工通信通道

// WebSocket 连接建立(基于HTTP升级)
Client  Server: HTTP GET + Upgrade: websocket
Client  Server: HTTP 101 Switching Protocols

// 此后保持TCP连接,双向实时通信
Client  Server: 实时数据交换(文本/二进制)

核心特点

  • 🔄 全双工:客户端和服务端可同时发送
  • 🌐 基于HTTP:通过HTTP升级建立连接
  • 🔗 持久连接:一次握手,长期通信
  • 📡 实时性:适合实时应用
  • 🏷️ 有协议头:有自己的帧格式

4. MQTT (消息队列遥测传输)

底层逻辑:基于TCP的轻量级发布订阅模式

// MQTT 通信流程
Client  Broker: CONNECT (建立连接)
Client  Broker: CONNACK (连接确认)

// 发布订阅模式
ClientA  Broker: PUBLISH(topic="sensors/temperature", payload=25)
Broker  ClientB: PUBLISH(topic="sensors/temperature", payload=25) // 推送给订阅者

核心特点

  • 📢 发布订阅:解耦消息生产者和消费者
  • 🪶 轻量级:协议头很小(最小2字节)
  • 🔋 低功耗:适合物联网设备
  • 📶 适应弱网络:有QoS等级应对网络问题
  • 🎯 主题过滤:通过主题路由消息

三、四者关系图解

┌─────────────────────────────────────────────────┐
│                   应用层 (Application Layer)       │
├─────────────────────────────────────────────────┤
│  ┌─────────────┐        ┌─────────────┐         │
│  │   MQTT      │        │ WebSocket   │         │
│  │ (Pub/Sub)   │        │(全双工通信)  │         │
│  └─────────────┘        └─────────────┘         │
└─────────────────────────────────────────────────┘
                          │
┌─────────────────────────────────────────────────┐
│                   传输层 (Transport Layer)        │
├─────────────────────────────────────────────────┤
│  ┌─────────────┐        ┌─────────────┐         │
│  │     TCP     │        │     UDP     │         │
│  │  (可靠连接)  │        │ (无连接数据报)│         │
│  └─────────────┘        └─────────────┘         │
└─────────────────────────────────────────────────┘
                          │
┌─────────────────────────────────────────────────┐
│                   网络层 (Network Layer)         │
│                   IP协议                         │
└─────────────────────────────────────────────────┘

四、依赖关系

基础依赖链

MQTT → TCP → IP
WebSocket → TCP → IP  
UDP → IP
TCP → IP

具体说明

  1. MQTT 依赖 TCP

    // MQTT 建立在TCP可靠性之上
    TCP保证: 连接可靠数据不丢失顺序正确
    MQTT专注: 消息路由主题管理QoS质量
    
  2. WebSocket 依赖 TCP

    // WebSocket 利用TCP的全双工特性
    TCP提供: 可靠的双向字节流
    WebSocket增强: 消息帧协议头实时通信
    
  3. UDP 与 TCP 是平级关系

    // 两者都是传输层协议,选择不同策略
    TCP: 要可靠性,牺牲速度
    UDP: 要速度,牺牲可靠性
    

五、协议选择决策树

func selectProtocol(requirements: AppRequirements) -> Protocol {
    if requirements.needsReliability {
        // 需要可靠性 → 基于TCP的协议
        if requirements.isMessageDriven {
            return .mqtt           // 发布订阅场景
        } else if requirements.needsRealTimeBidirectional {
            return .websocket      // 实时双向通信
        } else {
            return .tcp            // 普通可靠通信
        }
    } else {
        // 不需要可靠性 → UDP
        if requirements.isBroadcast || requirements.isLowLatency {
            return .udp            // 广播或低延迟场景
        } else {
            return .tcp            // 默认还是TCP
        }
    }
}

六、实际应用对比

使用场景推荐协议理由
设备控制命令MQTT可靠、支持QoS、适合IoT
实时视频流WebSocket全双工、实时性好
设备发现UDP广播无需连接、快速发现
传感器数据MQTT轻量、支持大量设备
固件升级TCP可靠传输大文件

代码示例对比

// TCP - 需要自己处理消息边界
func sendOverTCP(_ message: String) {
    let data = message.data(using: .utf8)!
    // 需要处理: 粘包、拆包问题
    outputStream.write(data: data)
}

// WebSocket - 自动处理消息帧
func sendOverWebSocket(_ message: String) {
    // 自动封装成WebSocket帧
    webSocket.send(message)
}

// MQTT - 基于主题的消息
func sendOverMQTT(_ message: String) {
    // 发布到特定主题
    mqttClient.publish("devices/123/control", message)
}

// UDP - 直接发送数据报
func sendOverUDP(_ message: String) {
    // 直接发送,不保证到达
    udpConnection.send(message.data(using: .utf8)!)
}

总结

核心关系

  1. TCP/UDP 是基础传输层协议,提供通信的基本能力
  2. WebSocket/MQTT 是应用层协议,在TCP基础上提供更高级的通信模式
  3. 选择策略
    • 要可靠性和高级功能 → 基于TCP的应用层协议
    • 要速度和简单性 → UDP
    • 实时双向通信 → WebSocket
    • 消息驱动和IoT场景 → MQTT

理解这些协议的分层和依赖关系,可以帮助你在不同场景下做出正确的技术选型。

基于 iOS Swift 开发,这几种协议都有对应的优秀库。我来为你推荐首选库和备选方案:

一、WebSocket 库推荐

🥇 首选:Starscream

// Podfile
pod 'Starscream'

// 使用示例
import Starscream

class WebSocketManager: WebSocketDelegate {
    private var socket: WebSocket?
    
    func connect() {
        var request = URLRequest(url: URL(string: "ws://yourserver.com/websocket")!)
        request.timeoutInterval = 5
        socket = WebSocket(request: request)
        socket?.delegate = self
        socket?.connect()
    }
    
    func websocketDidConnect(socket: WebSocketClient) {
        print("WebSocket连接成功")
    }
    
    func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {
        print("收到消息: \(text)")
    }
    
    func sendMessage(_ message: String) {
        socket?.write(string: message)
    }
}

优点

  • 纯 Swift 实现,性能优秀
  • 支持 iOS 8.0+
  • 活跃的维护和社区支持
  • 支持 SSL/TLS

对于 Objective-C 项目,有几个优秀的 WebSocket 库可以替代 Starscream:

🥇 首选:SocketRocket (Facebook 开发)

1. SocketRocket - 最接近 Starscream 的 OC 选择

// Podfile
pod 'SocketRocket'

// 使用示例
#import <SocketRocket/SRWebSocket.h>

@interface WebSocketManager () <SRWebSocketDelegate>
@property (nonatomic, strong) SRWebSocket *webSocket;
@end

@implementation WebSocketManager

- (void)connect {
    NSURL *url = [NSURL URLWithString:@"ws://yourserver.com/websocket"];
    self.webSocket = [[SRWebSocket alloc] initWithURL:url];
    self.webSocket.delegate = self;
    [self.webSocket open];
}

#pragma mark - SRWebSocketDelegate

- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
    NSLog(@"WebSocket连接成功");
}

- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
    if ([message isKindOfClass:[NSString class]]) {
        NSLog(@"收到文本消息: %@", message);
    } else if ([message isKindOfClass:[NSData class]]) {
        NSLog(@"收到二进制消息: %lu bytes", (unsigned long)[(NSData *)message length]);
    }
}

- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
    NSLog(@"WebSocket连接失败: %@", error);
}

- (void)sendMessage:(NSString *)message {
    [self.webSocket send:message];
}

@end

SocketRocket 特点

  • ✅ Facebook 开发维护,质量有保障
  • ✅ 纯 Objective-C 实现
  • ✅ 支持 iOS 6.0+
  • ✅ 自动重连机制
  • ✅ SSL/TLS 支持
  • ✅ 活跃的社区

🥈 备选方案

2. jetfire (Swift 库的 OC 兼容版本)

3. 使用 Apple 原生 Network.framework (iOS 12+)

#import <Network/NWWebSocket.h>

@interface NativeWebSocketManager ()
@property (nonatomic, strong) nw_connection_t connection;
@end

@implementation NativeWebSocketManager

- (void)connectWithURL:(NSURL *)url {
    nw_parameters_t parameters = nw_parameters_create_secure_tcp(
        NW_PARAMETERS_DISABLE_PROTOCOL,
        NW_PARAMETERS_DEFAULT_CONFIGURATION
    );
    
    nw_endpoint_t endpoint = nw_endpoint_create_url((__bridge CFStringRef)url.absoluteString);
    self.connection = nw_connection_create(endpoint, parameters);
    
    nw_connection_set_queue(self.connection, dispatch_get_main_queue());
    nw_connection_set_state_changed_handler(self.connection, ^(nw_connection_state_t state, nw_error_t error) {
        switch (state) {
            case nw_connection_state_ready:
                NSLog(@"WebSocket连接就绪");
                [self setupWebSocket];
                break;
            case nw_connection_state_failed:
                NSLog(@"WebSocket连接失败");
                break;
            default:
                break;
        }
    });
    
    nw_connection_start(self.connection);
}

- (void)setupWebSocket {
    // 使用 NWProtocolWebSocket
    nw_protocol_options_t websocket_options = nw_ws_create_options();
    // 配置 WebSocket 选项...
}

三、库对比矩阵

语言iOS版本维护状态推荐指数
SocketRocketObjective-C6.0+⭐⭐⭐⭐🥇 首选
jetfireSwift(OC兼容)8.0+⭐⭐⭐🥈 备选
Network.frameworkObjective-C12.0+⭐⭐⭐⭐⭐🥈 现代选择

五、完整项目集成示例

Podfile 配置

platform :ios, '9.0'

target 'YourObjectiveCApp' do
  # WebSocket
  pod 'SocketRocket'
  
  # 网络工具
  pod 'AFNetworking', '~> 4.0'
end

完整的 WebSocket 服务类

// WebSocketService.h
#import <Foundation/Foundation.h>
#import <SocketRocket/SRWebSocket.h>

NS_ASSUME_NONNULL_BEGIN

@protocol WebSocketServiceDelegate <NSObject>
- (void)webSocketDidReceiveMessage:(id)message;
- (void)webSocketConnectionStatusChanged:(BOOL)isConnected;
@end

@interface WebSocketService : NSObject <SRWebSocketDelegate>

@property (nonatomic, weak) id<WebSocketServiceDelegate> delegate;
@property (nonatomic, assign, readonly) BOOL isConnected;

+ (instancetype)shared;
- (void)connectToURL:(NSURL *)url;
- (void)disconnect;
- (void)sendMessage:(id)message;

@end

NS_ASSUME_NONNULL_END
// WebSocketService.m
#import "WebSocketService.h"

@interface WebSocketService ()
@property (nonatomic, strong) SRWebSocket *webSocket;
@property (nonatomic, assign) BOOL isConnected;
@end

@implementation WebSocketService

+ (instancetype)shared {
    static WebSocketService *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (void)connectToURL:(NSURL *)url {
    [self disconnect];
    
    self.webSocket = [[SRWebSocket alloc] initWithURL:url];
    self.webSocket.delegate = self;
    [self.webSocket open];
}

- (void)disconnect {
    [self.webSocket close];
    self.webSocket = nil;
    self.isConnected = NO;
}

- (void)sendMessage:(id)message {
    if (self.isConnected && self.webSocket) {
        [self.webSocket send:message];
    }
}

#pragma mark - SRWebSocketDelegate

- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
    self.isConnected = YES;
    [self.delegate webSocketConnectionStatusChanged:YES];
    NSLog(@"✅ WebSocket连接成功");
}

- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
    self.isConnected = NO;
    [self.delegate webSocketConnectionStatusChanged:NO];
    NSLog(@"❌ WebSocket连接失败: %@", error);
}

- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
    self.isConnected = NO;
    [self.delegate webSocketConnectionStatusChanged:NO];
    NSLog(@"🔌 WebSocket连接关闭: %ld %@", (long)code, reason);
}

- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
    [self.delegate webSocketDidReceiveMessage:message];
    NSLog(@"📨 收到WebSocket消息: %@", message);
}

@end

六、使用示例

// 在 ViewController 中使用
#import "WebSocketService.h"

@interface ViewController () <WebSocketServiceDelegate>
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [WebSocketService shared].delegate = self;
    NSURL *url = [NSURL URLWithString:@"ws://yourserver.com/websocket"];
    [[WebSocketService shared] connectToURL:url];
}

- (void)webSocketDidReceiveMessage:(id)message {
    // 处理收到的消息
    if ([message isKindOfClass:[NSString class]]) {
        NSLog(@"收到文本: %@", message);
    }
}

- (void)webSocketConnectionStatusChanged:(BOOL)isConnected {
    NSLog(@"连接状态: %@", isConnected ? @"已连接" : @"已断开");
}

- (IBAction)sendButtonTapped:(id)sender {
    [[WebSocketService shared] sendMessage:@"Hello from Objective-C!"];
}

@end

总结

推荐选择

  1. 🥇 SocketRocket - Objective-C 项目首选,功能完整,稳定可靠
  2. 🥈 Network.framework - 如果只支持 iOS 12+,使用苹果原生方案
  3. 🥉 jetfire - 如果需要 Swift/OC 混合开发

SocketRocket 的优势

  • ✅ 纯 Objective-C,无 Swift 依赖
  • ✅ 支持低版本 iOS (6.0+)
  • ✅ Facebook 维护,质量有保障
  • ✅ 功能完整,API 设计优秀
  • ✅ 社区活跃,文档丰富

对于现有的 Objective-C 项目,SocketRocket 是最适合的 Starscream 替代品

二、MQTT 库推荐

🥇 首选:CocoaMQTT

// Swift Package Manager 或 CocoaPods
// .package(url: "https://github.com/emqx/CocoaMQTT", from: "2.0.0")

import CocoaMQTT

class MQTTManager {
    private var mqttClient: CocoaMQTT?
    
    func connect() {
        let clientID = "iOS-\(UUID().uuidString)"
        mqttClient = CocoaMQTT(
            host: "your-broker.com",
            port: 1883,
            clientId: clientID
        )
        
        mqttClient?.username = "user"
        mqttClient?.password = "pass"
        mqttClient?.keepAlive = 60
        mqttClient?.delegate = self
        mqttClient?.connect()
    }
    
    func subscribeToTopic(_ topic: String) {
        mqttClient?.subscribe(topic)
    }
    
    func publishMessage(_ message: String, to topic: String) {
        mqttClient?.publish(topic, withString: message, qos: .qos1)
    }
}

extension MQTTManager: CocoaMQTTDelegate {
    func mqtt(_ mqtt: CocoaMQTT, didConnectAck ack: CocoaMQTTConnAck) {
        print("MQTT连接成功: \(ack)")
    }
    
    func mqtt(_ mqtt: CocoaMQTT, didReceiveMessage message: CocoaMQTTMessage, id: UInt16) {
        print("收到MQTT消息: \(message.string ?? "")")
    }
}

优点

  • 纯 Swift 实现
  • 完整的 MQTT 3.1.1 支持
  • 支持 QoS 0/1/2
  • 自动重连机制

🥈 备选:MQTTClient

// 基于 Objective-C,但非常稳定
pod 'MQTTClient'

三、TCP 库推荐

🥇 首选:Network.framework (Apple 官方)

import Network

class TCPManager {
    private var connection: NWConnection?
    private let queue = DispatchQueue(label: "tcp.manager")
    
    func connect(host: String, port: Int) {
        let host = NWEndpoint.Host(host)
        let port = NWEndpoint.Port("\(port)")!
        
        connection = NWConnection(host: host, port: port, using: .tcp)
        
        connection?.stateUpdateHandler = { [weak self] state in
            switch state {
            case .ready:
                print("TCP连接就绪")
                self?.startReceiving()
            case .failed(let error):
                print("TCP连接失败: \(error)")
            default:
                break
            }
        }
        
        connection?.start(queue: queue)
    }
    
    private func startReceiving() {
        connection?.receive(minimumIncompleteLength: 1, maximumLength: 65536) { [weak self] data, _, isComplete, error in
            if let data = data, !data.isEmpty {
                self?.handleReceivedData(data)
            }
            
            if error == nil && !isComplete {
                self?.startReceiving()
            }
        }
    }
    
    func sendData(_ data: Data) {
        connection?.send(content: data, completion: .contentProcessed { error in
            if let error = error {
                print("TCP发送失败: \(error)")
            }
        })
    }
}

优点

  • Apple 官方框架,兼容性最好
  • 支持 iOS 12.0+
  • 现代 API 设计
  • 支持 TLS

🥈 备选:BlueSocket

// Swift Package Manager
// .package(url: "https://github.com/Kitura/BlueSocket", from: "2.0.0")

四、UDP 库推荐

🥇 首选:Network.framework (Apple 官方)

import Network

class UDPSocket {
    private var connection: NWConnection?
    private let queue = DispatchQueue(label: "udp.socket")
    
    func setupUDP(host: String, port: Int) {
        let host = NWEndpoint.Host(host)
        let port = NWEndpoint.Port("\(port)")!
        
        connection = NWConnection(host: host, port: port, using: .udp)
        
        connection?.stateUpdateHandler = { state in
            switch state {
            case .ready:
                print("UDP就绪")
                self.startReceiving()
            default:
                break
            }
        }
        
        connection?.start(queue: queue)
    }
    
    private func startReceiving() {
        connection?.receiveMessage { [weak self] data, context, isComplete, error in
            if let data = data {
                self?.handleUDPData(data)
            }
            self?.startReceiving()
        }
    }
    
    func sendUDPData(_ data: Data) {
        connection?.send(content: data, completion: .idempotent)
    }
    
    // 广播功能
    func broadcast(data: Data, port: Int) {
        let broadcastHost = NWEndpoint.Host("255.255.255.255")
        let broadcastPort = NWEndpoint.Port("\(port)")!
        
        let broadcastConnection = NWConnection(host: broadcastHost, port: broadcastPort, using: .udp)
        broadcastConnection.send(content: data, completion: .idempotent)
        broadcastConnection.start(queue: queue)
    }
}

五、综合网络库推荐

🥇 首选:Alamofire + 上述专业库

对于 HTTP 请求,推荐使用 Alamofire:

// Podfile
pod 'Alamofire'

import Alamofire

class NetworkService {
    func requestDeviceStatus(deviceId: String) async throws -> DeviceStatus {
        return try await AF.request(
            "https://api.example.com/devices/\(deviceId)/status",
            method: .get
        )
        .validate()
        .serializingDecodable(DeviceStatus.self)
        .value
    }
    
    func sendControlCommand(_ command: ControlCommand) async throws {
        try await AF.request(
            "https://api.example.com/control",
            method: .post,
            parameters: command,
            encoder: JSONParameterEncoder.default
        )
        .validate()
        .serializingString()
        .value
    }
}

六、库选择决策矩阵

协议首选库备选库推荐理由
WebSocketStarscream-纯Swift,性能优秀
MQTTCocoaMQTTMQTTClient纯Swift,功能完整
TCPNetwork.frameworkBlueSocket官方支持,现代API
UDPNetwork.framework-官方支持,简单易用
HTTPAlamofireURLSession功能丰富,生态完善

七、实际项目集成示例

// 网络管理器整合 class PetDeviceNetworkManager { private let mqttManager = MQTTManager() private let webSocketManager = WebSocketManager() private let httpService = NetworkService()

func setupNetworking() {
    // MQTT用于设备控制和状态更新
    mqttManager.connect()
    mqttManager.subscribeToTopic("pets/+/status")
    
    // WebSocket用于实时视频流
    webSocketManager.connect()
    
    // HTTP用于配置和文件上传
    // 使用 Alamofire
}

func sendFeedingCommand(petId: String, amount: Double) {
    let command = FeedingCommand(petId: petId, amount: amount)
    mqttManager.publishMessage(command.jsonString, to: "pets/\(petId)/commands")
}

func startVideoStream(petId: String) {
    webSocketManager.sendMessage("start_stream:\(petId)")
}

}


## 八、依赖管理建议

### **CocoaPods 配置**:
```ruby
# Podfile
platform :ios, '13.0'

target 'YourPetApp' do
  # WebSocket
  pod 'Starscream', '~> 4.0'
  
  # MQTT
  pod 'CocoaMQTT', '~> 2.0'
  
  # HTTP
  pod 'Alamofire', '~> 5.0'
  
  # 工具类
  pod 'SwiftyJSON', '~> 5.0'
end

Swift Package Manager 配置

// Package.swift
dependencies: [
    .package(url: "https://github.com/daltoniam/Starscream", from: "4.0.0"),
    .package(url: "https://github.com/emqx/CocoaMQTT", from: "2.0.0"),
    .package(url: "https://github.com/Alamofire/Alamofire", from: "5.0.0")
]

总结

推荐组合

  1. WebSocket: Starscream
  2. MQTT: CocoaMQTT
  3. TCP/UDP: Network.framework (Apple官方)
  4. HTTP: Alamofire

选择理由

  • 纯 Swift 实现:更好的性能和类型安全
  • 活跃维护:长期支持和更新
  • 良好文档:学习成本低
  • 社区支持:问题容易解决
  • iOS 兼容性:支持较旧的 iOS 版本

防丢包需要根据不同的协议和场景采用不同的策略。让我为你详细介绍各种防丢包方案:

一、TCP 层面的防丢包(自动处理)

TCP 本身已经内置了完善的防丢包机制:

1. TCP 自动重传机制

// TCP 自动处理丢包,开发者无需关心
class TCPConnection {
    func sendData(_ data: Data) {
        // TCP 底层自动处理:
        // ✅ 序列号:检测丢失和乱序
        // ✅ 确认机制:接收方确认收到
        // ✅ 超时重传:未确认的数据自动重发
        // ✅ 快速重传:收到3个重复ACK立即重传
        outputStream.write(data: data)
    }
}

2. TCP 参数优化

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. 基础确认重传机制

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)

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. 消息确认机制

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. 数据分片和重组

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 等级

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. 应用层心跳和重连

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. 消息确认机制

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. 动态调整策略

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("📉 网络质量差,降低传输速率")
    }
}

七、综合防丢包方案

混合策略管理器

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使用QoSQoS1/QoS2、持久会话
WebSocket应用层确认心跳、消息ID、重连
大文件传输分片传输数据分片、选择性重传
实时数据前向纠错添加冗余数据

关键原则

  1. TCP优先:能用TCP就不要用UDP
  2. 分层防护:传输层+应用层双重保障
  3. 自适应:根据网络状况动态调整策略
  4. 监控反馈:实时监控丢包率并调整参数

根据你的具体应用场景选择合适的防丢包组合策略。