【iOS】smartconfig 廣播實(shí)現(xiàn)

一、框架

1.UDP框架 GCDAsyncUdpSocket;
2.加密方式,采用aes_cfb128 iv為0 ;
3.抓包驗(yàn)證wireshark

二、數(shù)據(jù)初始化

1.初始化UDPSocket

_castSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:_castQueue];

(1)開啟廣播 Broadcast;

if (![_castSocket enableBroadcast:YES error:&error]) {
     UdpLog(@"enableBroadcast error:%@",error);
}

(2)接收數(shù)據(jù) beginReceiving;

if (![_castSocket beginReceiving:&error]) {
     UdpLog(@"beginReceiving error:%@",error);
}

(3)指定端口 不指定則會隨機(jī)分配;

三、數(shù)據(jù)發(fā)送

(1)發(fā)送地址

端口與設(shè)備端協(xié)商,這里以60000舉例
local:port -> 192.168.2.255 : 60000 + index

(2)數(shù)據(jù)
說明
dataByte 總長度(1) + flag(1) + ssidLen(1) + pwdLen(1) + ssid + pwd + checkSum(2)
ssid: ssid為中文則采用utf-8編碼,其他則為ASCII編碼
pwd pwd需要加密
checkSum 校驗(yàn)和
//判斷中文
- (BOOL)isChinese:(NSString *) str{
    for(int i=0; i< [str length];i++){
        int a = [str characterAtIndex:i];
        if( a > 0x4E00 && a < 0x9FFF){
            return YES;
        }
    }
    return NO;
}
//aes加密
- (NSData *)gnAesEncryptData:(uint8_t *)crypt_data len:(int)crypt_len keyData:(NSData *)keydata{
    unsigned char *keyResult=(Byte*)[keydata bytes];
    AES_KEY aes_key;
    unsigned char *outByte = NULL;
    outByte = (unsigned char *)malloc(crypt_len+1);
    memset(outByte, 0, crypt_len+1);
    AES_set_encrypt_key(keyResult, 128, &aes_key);
    int number = 0;
    NSData *ivData = [NSData dataWithBytes:&number length:1];
    unsigned char *ivResult = (Byte*)[ivData bytes];
    NSData *numData = [NSData dataWithBytes:&number length:1];
    int *numResult = (int *)[numData bytes];
    AES_cfb128_encrypt(crypt_data,outByte,crypt_len, &aes_key,ivResult,numResult ,AES_ENCRYPT);
    NSData *Decrydata = [NSData dataWithBytes:outByte length:crypt_len];
    return Decrydata;
}
(3)發(fā)送結(jié)構(gòu)

利用廣播的數(shù)據(jù)長度length發(fā)送數(shù)據(jù) 每次發(fā)送11bit數(shù)據(jù),
幀頭與設(shè)備端協(xié)商,這里以0x480舉例
數(shù)據(jù)分為

說明
幀頭 0x480 , 0x481,0x482,0x483…
幀數(shù)據(jù) index(4bit) + data(7bit)

bit7 幀頭固定為1 ,數(shù)據(jù)幀固定為0;
發(fā)送數(shù)按組發(fā)送 一組是一個(gè)幀頭*2 + 8個(gè)數(shù)據(jù)幀;

[self.castClient sendData:[self zeroDataWithCount:value] toHost:_broadcastIP port:60000+_sendCount];
(4)轉(zhuǎn)碼

由于bit7是幀頭位, 所以每次只能發(fā)送6bit數(shù)據(jù),就需要對整個(gè)數(shù)據(jù) 進(jìn)行8bit->6bit轉(zhuǎn)碼
例如

 0x 11 22 (0b 0001 0001 0010 0010 (高位到低位)) -> 1000 1000 0100 0100(低位到高位)
-> 100010 000100 010000(低位到高位) -> 010001 001000  0000010(高位到低位) ->0x11 08 02 
    int  bitCount = 6;
    int  dataLength = (int)data.length;
    Byte codeData[dataLength * bitCount];
    int  outLength = (dataLength * 8 + bitCount - 1) /bitCount;
    Byte outData[outLength];
    Byte *dataByte = (Byte *)data.bytes;
    for (int i = 0; i < dataLength; i ++) {
        for (int j = 0; j < 8; j++) {
            codeData[i * 8 + j] = (dataByte[i] >> j) & 0x01;
        }
    }
    for (int i = 0; i < outLength; i++) {
        outData[i] = 0;
        for (int j = 0; j < bitCount; j ++) {
            outData[i] |= codeData[i * bitCount + j] << j;
        }
    }
    NSData *tempCodeData = [NSData dataWithBytes:outData length:sizeof(outData)];
    return  tempCodeData;
(5)傳輸規(guī)則

每包之間間隔20ms;間隔時(shí)間可按實(shí)際情況調(diào)整
(1) 幀頭*2 (0x480 -> 1152)
(2) 幀數(shù)據(jù) 8 (組序號<<7 + data[index])
(3) 幀頭
2 (0x481 -> 1153)
(4) 幀數(shù)據(jù) 8
(5) 幀頭
2 (0x482 -> 1154)

(6) 幀數(shù)據(jù) *8
...


截屏2021-04-29 15.49.01.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容