通讯协议实现相关模块 Big-endian大端方式存储

最近遇到的问题,网上大多人都在搜这样的没有结果,昨天捣鼓到2点多才有一点点的思路。不过也多亏啦小丁学长的帮助。
题目要求是这样的:
现在有如下通信协议,请实现相关函数模块。
此协议是一个二进制协议,每个协议报文由如下数据流构成,数值都以Big-endian大端方式存储:
{ TotalSize[2], Crc32[4], Ver[1], Cmd[1], Data[len] }

方括号中是占用的字节数。具体解释:
TotalSize: 2字节,表示整个报文的长度,这个值应该等于: 2 + 4 + 1 + 1 + len
Crc32: 4字节,表示对 {Ver, Cmd, Data} 内容的 crc32 的校验值
Ver: 1字节,协议版本,目前约定为 0x05
Cmd: 1字节,用户指定的操作命令,0x00 ~ 0xff
Data: len个字节,具体的数据内容

要求:实现一个函数 pack(cmd, data, len)
输入:cmd: 用户指定的操作命令; data: 用户指定的数据; len: 数据长度
输出:打包好的协议报文

首先理解一下几个问题:

  1. 什么是大端,什么是小端:
    所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
    所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。
    2.为什么会有大小端:
    为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
    3.大小端在内存中的存放方式举例:
    例如,16bit宽的数0x1234在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
    内存地址
    0x4000
    0x4001
    存放内容
    0x34
    0x12
    而在Big-endian模式CPU内存中的存放方式则为:
    内存地址
    0x4000
    0x4001
    存放内容
    0x12
    0x34

32bit宽的数0x12345678在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址
0x4000
0x4001
0x4002
0x4003
存放内容
0x78
0x56
0x34
0x12
而在Big-endian模式CPU内存中的存放方式则为:
内存地址
0x4000
0x4001
0x4002
0x4003
存放内容
0x12
0x34
0x56
0x78

4.如何测试编译器是大端还是小端:
下面这段代码可以用来测试一下你的编译器是大端模式还是小端模式:

#include<stdio.h>

int main()
{
    short int x;
    char x0,x1;
    x=0x1122;
    x0=((char *)&x)[0];  //低地址单元
    x1=((char *)&x)[1];  //高地址单元
    printf("x0=0x%x,x1=0x%x",x0,x1);// 若x0=0x11,则是大端; 若x0=0x22,则是小端......
    return 0;
}

对于这个问题来说,对于IOS开发者,还好理解IOS的底层,IOS小端内存布局 但是网络传输是大端内存布局。那么就需要转换一下,如何转换呢。直接上代码,源码下载地址:`https://github.com/HeroGuo/HG_Socket.git:
Step1:首先在工程中导入Libz.tbd
Step2:代码如下:

- (NSData *)pack:(NSString *)cmd data:(NSString *)data {
    NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(NSUTF16BigEndianStringEncoding);
    Byte ver[1] = {0x05};
    NSData *verData = [NSData dataWithBytes:ver length:1];

    Byte cmdBytes[2];
    NSData *cmdDataTemp = [cmd dataUsingEncoding:encoding];
    if (cmdDataTemp.length >= 2) {
        for (int i = 0; i < 2; i++) {
            cmdBytes[i] = ((Byte *)[cmdDataTemp bytes])[i];
        }
    } else {
        cmdBytes[0] = ((Byte *)[cmdDataTemp bytes])[0];
    }
    NSData *cmdData = [NSData dataWithBytes:cmdBytes length:2];

    NSData *inputData = [data dataUsingEncoding:encoding];
    int datalength = (int)inputData.length;
    NSMutableData *crcData = [NSMutableData data];
    [crcData appendData:verData];
    [crcData appendData:cmdData];
    [crcData appendData:inputData];

    int crc;
    crc32(crc, [crcData bytes], (unsigned int)crcData.length);
    unsigned char *pCrc = (unsigned char *)&crc;
    Byte crcBytes[4];
    for (int i = 0; i < 4; i++) {
        crcBytes[i] = *pCrc;
        pCrc++;
    }
    NSData *crc32Data = [NSData dataWithBytes:crcBytes length:4];

    int messageLength = datalength + 6;
    Byte lengthBytes[2];
    unsigned char *pLength = (unsigned char *)&messageLength;
    for (int i = 0; i < 2; i++) {
        lengthBytes[i] = *pLength;
        pLength++;
    }
    NSData *lengthData = [NSData dataWithBytes:lengthBytes length:2];

    NSMutableData *messageData = [NSMutableData data];
    [messageData appendData:lengthData];
    [messageData appendData:crc32Data];
    [messageData appendData:verData];
    [messageData appendData:cmdData];
    [messageData appendData:inputData];

    return [messageData copy];
}
[源码下载地址:`https://github.com/HeroGuo/HG_Socket.git](https://github.com/HeroGuo/HG_Socket.git)

Step3:优化CRC32

//crc32实现函数
unsigned int CRC32( unsigned char *buf, int len) {
    uint32_t *table = malloc(sizeof(uint32_t) * 256);
    uint32_t crc = 0xffffffff;

    for (uint32_t i=0; i<256; i++) {
        table[i] = i;
        for (int j=0; j<8; j++) {
            if (table[i] & 1) {
                table[i] = (table[i] >>= 1) ^ 0xedb88320;
            } else {
                table[i] >>= 1;
            }
        }
    }

    for (int i=0; i<len; i++) {
        crc = (crc >> 8) ^ table[crc & 0xff ^ buf[i]];
    }
    crc ^= 0xffffffff;

    free(table);
    return crc;
}
[源码下载地址:`https://github.com/HeroGuo/HG_Socket.git](https://github.com/HeroGuo/HG_Socket.git)`

源码下载地址:https://github.com/HeroGuo/HG_Socket.git

你可能感兴趣的:(ios,socket,通信,二进制,big-endian)