MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Objective-C与物联网(IoT)设备通信案例

2021-05-167.1k 阅读

物联网(IoT)概述

物联网(Internet of Things,IoT)是通过感知设备、网络通信技术将各种物体连接到互联网,实现数据的采集、传输、处理和交互,从而使物体能够智能化地协同工作的网络。在物联网系统中,设备种类繁多,包括传感器、执行器等,它们需要与后端服务器以及其他设备进行通信。

Objective - C 语言在物联网开发中的地位

Objective - C 作为一种强大的面向对象编程语言,在苹果生态系统中广泛应用。对于开发运行在 iOS 和 macOS 设备上与物联网设备交互的应用程序,Objective - C 提供了丰富的库和框架来实现通信功能。它可以利用苹果设备的硬件特性,如蓝牙、Wi - Fi 等模块,与物联网设备进行高效通信。

物联网设备通信方式

蓝牙通信

蓝牙是一种短距离无线通信技术,常用于物联网设备与移动设备之间的通信。在 Objective - C 开发中,可以使用 Core Bluetooth 框架来实现与蓝牙设备的交互。

例如,扫描附近的蓝牙设备代码如下:

#import <CoreBluetooth/CoreBluetooth.h>

@interface BluetoothScanner : NSObject <CBCentralManagerDelegate>

@property (nonatomic, strong) CBCentralManager *centralManager;

@end

@implementation BluetoothScanner

- (instancetype)init {
    self = [super init];
    if (self) {
        _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
    }
    return self;
}

- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    if (central.state == CBCentralManagerStatePoweredOn) {
        [central scanForPeripheralsWithServices:nil options:nil];
    }
}

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {
    NSLog(@"Discovered peripheral: %@ with RSSI: %@", peripheral.name, RSSI);
}

@end

在上述代码中,首先创建了一个 CBCentralManager 实例,并设置其代理为当前类实例。当蓝牙设备状态变为可用(CBCentralManagerStatePoweredOn)时,开始扫描周边设备。一旦发现设备,centralManager:didDiscoverPeripheral:advertisementData:RSSI: 代理方法会被调用,在这个方法中可以获取到设备的名称和信号强度等信息。

Wi - Fi 通信

Wi - Fi 适用于需要较长距离或较高数据传输速率的物联网设备通信场景。在 Objective - C 中,可以使用 CFNetwork 框架进行基于 Wi - Fi 的网络通信。以下是一个简单的 HTTP 请求示例,假设物联网设备提供了一个 HTTP API 接口来获取数据:

#import <Foundation/Foundation.h>

@interface IoTHTTPRequest : NSObject

- (void)fetchDataFromIoTServer;

@end

@implementation IoTHTTPRequest

- (void)fetchDataFromIoTServer {
    NSURL *url = [NSURL URLWithString:@"http://iotdevice.example.com/api/data"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"GET"];

    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (!error && data) {
            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"Received data from IoT device: %@", responseString);
        } else {
            NSLog(@"Error: %@", error);
        }
    }];
    [task resume];
}

@end

在这段代码中,首先创建了一个指向物联网设备 API 地址的 NSURL 对象,然后构造了一个 NSMutableURLRequest 对象并设置请求方法为 GET。接着使用 NSURLSession 创建一个数据任务,在任务的完成处理块中处理从物联网设备返回的数据或错误信息。

案例一:基于蓝牙的温湿度传感器数据采集

硬件设备

假设我们有一个基于蓝牙的温湿度传感器设备,该设备支持蓝牙低功耗(BLE)协议。传感器设备周期性地测量环境温度和湿度,并通过蓝牙将数据发送出去。

软件实现

  1. 扫描蓝牙设备: 利用前面提到的 Core Bluetooth 框架扫描周边蓝牙设备,寻找我们的温湿度传感器设备。假设传感器设备的 UUID 为已知值,我们可以在扫描时过滤出该设备。
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    if (central.state == CBCentralManagerStatePoweredOn) {
        CBUUID *sensorServiceUUID = [CBUUID UUIDWithString:@"12345678 - 1234 - 5678 - 1234 - 567812345678"];
        [central scanForPeripheralsWithServices:@[sensorServiceUUID] options:nil];
    }
}
  1. 连接设备: 当发现目标温湿度传感器设备后,建立连接。
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {
    if ([peripheral.identifier.UUIDString isEqualToString:@"specific - sensor - uuid"]) {
        [central connectPeripheral:peripheral options:nil];
    }
}

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    NSLog(@"Connected to temperature - humidity sensor");
    [peripheral discoverServices:nil];
}
  1. 发现服务和特征: 连接成功后,发现设备提供的服务和特征。温湿度传感器可能会将温度和湿度数据分别通过不同的特征值来传输。
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
    for (CBService *service in peripheral.services) {
        [peripheral discoverCharacteristics:nil forService:service];
    }
}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
    for (CBCharacteristic *characteristic in service.characteristics) {
        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"temperature - characteristic - uuid"]]) {
            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
        } else if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"humidity - characteristic - uuid"]]) {
            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
        }
    }
}
  1. 接收数据: 当传感器设备有新数据时,会通过通知的方式将数据发送过来,我们在代理方法中接收并处理数据。
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"temperature - characteristic - uuid"]]) {
        NSData *data = characteristic.value;
        float temperature = [self convertDataToTemperature:data];
        NSLog(@"Received temperature: %f", temperature);
    } else if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"humidity - characteristic - uuid"]]) {
        NSData *data = characteristic.value;
        float humidity = [self convertDataToHumidity:data];
        NSLog(@"Received humidity: %f", humidity);
    }
}

- (float)convertDataToTemperature:(NSData *)data {
    // 假设数据格式为 2 字节的整数,这里进行实际的转换逻辑
    int16_t value;
    [data getBytes:&value length:sizeof(int16_t)];
    return value / 100.0;
}

- (float)convertDataToHumidity:(NSData *)data {
    // 假设数据格式为 2 字节的整数,这里进行实际的转换逻辑
    int16_t value;
    [data getBytes:&value length:sizeof(int16_t)];
    return value / 100.0;
}

在上述代码中,通过一系列的步骤实现了与蓝牙温湿度传感器的通信,从扫描设备、连接、发现服务和特征,到最终接收并处理传感器数据。

案例二:通过 Wi - Fi 控制智能开关

硬件设备

智能开关设备具备 Wi - Fi 通信模块,能够接收网络指令并控制电器的通断。设备内置一个简单的 HTTP 服务器,用于接收控制指令。

软件实现

  1. 发送控制指令: 在 iOS 应用中,使用 CFNetworkNSURLSession 向智能开关设备的 HTTP 服务器发送控制指令。假设智能开关的 IP 地址为 192.168.1.100,控制接口为 /api/switch,通过 POST 请求发送开关状态(onoff)。
- (void)sendSwitchCommand:(NSString *)command {
    NSURL *url = [NSURL URLWithString:@"http://192.168.1.100/api/switch"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];
    NSString *parameters = [NSString stringWithFormat:@"status=%@", command];
    NSData *postData = [parameters dataUsingEncoding:NSUTF8StringEncoding];
    [request setHTTPBody:postData];
    [request setValue:@"application/x - www - form - urlencoded" forHTTPHeaderField:@"Content - Type"];

    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (!error && data) {
            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"Command response: %@", responseString);
        } else {
            NSLog(@"Error: %@", error);
        }
    }];
    [task resume];
}
  1. 接收设备状态反馈: 智能开关设备在接收到指令并执行后,可能会返回当前开关的状态。可以通过另一个 API 接口,如 /api/status,使用 GET 请求获取状态。
- (void)fetchSwitchStatus {
    NSURL *url = [NSURL URLWithString:@"http://192.168.1.100/api/status"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"GET"];

    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (!error && data) {
            NSString *statusString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"Switch status: %@", statusString);
        } else {
            NSLog(@"Error: %@", error);
        }
    }];
    [task resume];
}

通过上述代码实现了与 Wi - Fi 智能开关设备的通信,能够发送控制指令并获取设备状态反馈。

安全性考虑

在物联网设备通信中,安全性至关重要。无论是蓝牙还是 Wi - Fi 通信,都可能面临数据泄露、中间人攻击等风险。

蓝牙安全

  1. 配对和认证: 在蓝牙连接过程中,可以使用配对机制,通过交换安全密钥来认证设备身份。在 Objective - C 中,Core Bluetooth 框架支持设备配对,例如:
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    [peripheral setConnectionState:CBPeripheralConnectionStateConnected options:@{CBConnectPeripheralOptionNotifyOnConnectionKey:@YES, CBConnectPeripheralOptionNotifyOnDisconnectionKey:@YES, CBConnectPeripheralOptionNotifyOnNotificationKey:@YES}];
    [peripheral setNotifyValue:YES forCharacteristic:characteristic];
    if (peripheral.state == CBPeripheralStateConnected) {
        [peripheral setPairingDelegate:self];
        [peripheral performPairing];
    }
}

- (void)peripheral:(CBPeripheral *)peripheral didFailToPairWithError:(NSError *)error {
    NSLog(@"Pairing failed: %@", error);
}

- (void)peripheralDidUpdateName:(CBPeripheral *)peripheral {
    NSLog(@"Device name updated: %@", peripheral.name);
}

- (void)peripheralDidUpdateState:(CBPeripheral *)peripheral {
    if (peripheral.state == CBPeripheralStateDisconnected) {
        NSLog(@"Device disconnected");
    }
}

在上述代码中,当连接到设备后,调用 performPairing 方法进行配对,配对过程中相关的代理方法会处理配对成功或失败的情况。

  1. 数据加密: 蓝牙低功耗(BLE)协议本身支持加密传输,在连接建立后,数据在传输过程中会被加密,防止数据被窃取或篡改。

Wi - Fi 安全

  1. HTTPS 通信: 对于基于 Wi - Fi 的 HTTP 通信,应使用 HTTPS 协议代替 HTTP。在 Objective - C 中,可以通过设置 NSURLSession 的配置来支持 HTTPS。
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.HTTPAdditionalHeaders = @{@"Accept": @"application/json"};
configuration.TLSMaximumSupportedProtocol = kTLSProtocol12;
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];

通过上述配置,设置了支持的最高 TLS 协议版本为 1.2,确保通信的安全性。

  1. 设备认证: 在与物联网设备建立连接时,通过服务器端的证书验证设备的身份,防止中间人攻击。可以使用 NSURLSessionDelegate 中的方法来处理证书验证。
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler {
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
        NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
    } else {
        completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
    }
}

在上述代码中,当接收到服务器的认证挑战时,检查认证方法是否为服务器信任验证,如果是,则创建一个基于服务器信任的证书凭证,并通过完成处理块返回,以完成认证过程。

优化通信性能

  1. 减少数据传输量: 在物联网设备通信中,数据传输量应尽量精简。对于蓝牙通信,避免频繁传输大量数据,例如对于温湿度传感器,可以根据实际需求调整数据发送频率。对于 Wi - Fi 通信,在构造 HTTP 请求和响应时,只传输必要的数据字段。

  2. 优化网络连接: 对于 Wi - Fi 连接,合理设置 NSURLSession 的超时时间,避免长时间等待造成的资源浪费。

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.timeoutIntervalForRequest = 10.0; // 设置请求超时时间为 10 秒
configuration.timeoutIntervalForResource = 60.0; // 设置资源加载超时时间为 60 秒
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
  1. 处理连接中断: 在蓝牙或 Wi - Fi 通信过程中,可能会出现连接中断的情况。在 Objective - C 中,可以通过相关框架的代理方法来处理连接中断,并进行自动重连。 对于蓝牙,在 centralManager:didDisconnectPeripheral:error: 代理方法中处理:
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSLog(@"Disconnected from peripheral: %@", error);
    // 进行自动重连逻辑
    [central connectPeripheral:peripheral options:nil];
}

对于 Wi - Fi,在 NSURLSessionTaskDelegateURLSession:task:didCompleteWithError: 方法中处理:

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    if (error) {
        NSLog(@"Connection error: %@", error);
        // 进行重连逻辑,例如重新创建并启动任务
        [self sendRequestAgain];
    }
}

通过上述方法,可以有效优化 Objective - C 与物联网设备的通信性能,确保通信的稳定性和高效性。同时,注重安全性,防止数据泄露和恶意攻击,为物联网应用的开发提供可靠的基础。在实际开发中,还需要根据具体的物联网设备和应用场景进行灵活调整和优化。