iOS-二进制协议的封装

版权所有,禁止匿名转载;禁止商业使用。

对于在SDK socket通信时会存在二进制协议的通信模式,对于此根据以往的工作内容进行小结:


首先在socket通讯中可以有字符串协议和二进制协议,通过协议来达到通讯的目的。对于字符串协议就是通过字符串来制定通讯的标准模式是“string”-“value”模式,通过XML或者json来达到网络传输,解析封装也是基于XML或者json进行信息提取。


对于二进制协议,在C语言是通过struct对协议进行封装,在iOS中使用的是OC,在OC中你也可以通过C语言对二进制协议进行封装,但是在C语言和OC混合变成就会感觉好不爽。所以今天就通过OC谈一谈二进制协议封装。


首先C语言对协议的封装进行分解,一个Struct结构体无非就是协议值的布局,协议值占的byte数,包的大小,结构体的内存块。通过一一对应关系,我们就可以把结构体映射到OC的类中。下面通过一个简单的协议封装结构题和OC的协议封装来理解:


比如现在有一个协议的C语言结构如下


struct {
  char one;//字符
  unsigned short two;  //short类型
  unsigned int three;//int类型
  char * four;//字符串
}BinaryProtocolStruct;

使用OC面向对象的思想对该协议进行封装


头文件:


@interface BinaryProtocolTest : NSObject
-(id)initWithOne:(int)one andTwo:(int)two andThree:(int)three andFour:(NSString *)string;
-(id)initWithData:(NSData *)data;
-(void)setOne:(int)one;
-(void)setTwo:(int)two;
-(void)setThree:(int)three;
-(void)setFour:(NSString *)four;
-(int)getOne;
-(int)getTwo;
-(int)getThree;
-(NSString *)getFour;
-(NSMutableData *)getProtocolData;
-(int)getProtocolSize;
+(int)getProtocolSize;
@end

实现文件:


//协议的固定大小
#define ProtocolSize 39
@implementation BinaryProtocolTest{
  NSMutableData *_protocolData; //协议的内存块
  int _protocolSize;  //协议的内存块大小
  struct{
    unsigned short one_offset:8;
    unsigned short one_len:8;
    unsigned short two_offset:8;
    unsigned short two_len:8;
    unsigned short three_offset:8;
    unsigned short three_len:8;
    unsigned short four_offset:8;
    unsigned short four_len:8;
  }_protocolLayout;  //协议的内存块布局,主要由offset和size决定
}
-(void)initProtocolLayout{
  _protocolLayout.one_offset=0;
  _protocolLayout.one_len = 1;
  _protocolLayout.two_offset = 1;
  _protocolLayout.two_len = 2;
  _protocolLayout.three_offset = 3;
  _protocolLayout.three_len =4;
  _protocolLayout.four_offset =7;
  _protocolLayout.four_len =32;
  _protocolSize = 39;
}
/*
 *该方法的主要作用是当你想使用该协议封装自己的数据时使用
 */
-(id)initWithOne:(int)one andTwo:(int)two andThree:(int)three andFour:(NSString *)four{
  self = [super init];
  if (self) {
    [self initProtocolLayout];  //先初始化协议的内存布局
    _protocolData = [[NSMutableData alloc]init];//初始化协议的内存块
    [_protocolData resetBytesInRange:NSMakeRange(0, _protocolSize)];//设定内存块的大小
    //one为char类型不需要进行网络主机传输模式转换,把one的值写入到内存块中
    unsigned char tempOne = one;
    [_protocolData replaceBytesInRange:NSMakeRange(_protocolLayout.one_offset, _protocolLayout.one_len) withBytes:&tempOne length:_protocolLayout.one_len];
    //two为unsigned short 类型,所以要进行网络主机的传输字节顺序的转换 htons ->short 类型的主机存储->网络的网络存储,并写入内存块
    unsigned short tempTwo = two;
    tempTwo = htons(tempTwo);
    [_protocolData replaceBytesInRange:NSMakeRange(_protocolLayout.two_offset, _protocolLayout.two_len) withBytes:&tempTwo length:_protocolLayout.two_len];
    //three 为int类型 所以要进行网络主机的传输字节顺序的转换 htonl ->short 类型的主机存储->网络的网络存储,并写入内存块
    unsigned int tempThree = three;
    tempThree = htonl(tempThree);
    [_protocolData replaceBytesInRange:NSMakeRange(_protocolLayout.three_offset, _protocolLayout.three_len) withBytes:&tempThree length:_protocolLayout.three_len];
    //four为字符串不需要进行存储转换
    NSData *tempFour = [four dataUsingEncoding:NSUTF8StringEncoding];
    [_protocolData replaceBytesInRange:NSMakeRange(_protocolLayout.four_offset, _protocolLayout.four_len) withBytes:tempFour.bytes length:_protocolLayout.four_len];
  }
  return self;
}
-(id)init{
  self = [super init];
  if (self) {
    [self initProtocolLayout];
    _protocolData = [[NSMutableData alloc] init];
    [_protocolData resetBytesInRange:NSMakeRange(0, _protocolSize)];
  }
  return self;
}
-(id)initWithData:(NSData *)data{
  self = [super init];
  if (self) {
    [self initProtocolLayout];
    if (data.length!=_protocolSize) {
      return nil; //参数过滤,如果返回的数据包的大小不对,就返回
    }
    _protocolData = [[NSMutableData alloc] init];
    [_protocolData resetBytesInRange:NSMakeRange(0, _protocolSize)];
    [_protocolData replaceBytesInRange:NSMakeRange(0, _protocolSize) withBytes:data.bytes length:_protocolSize];
  }
  return self;
}
//one的设置 char
-(void)setOne:(int)one{
  if (_protocolData.length !=_protocolSize) {
    //one为char类型不需要进行网络主机传输模式转换,把one的值写入到内存块中
    unsigned char tempOne = one;
    [_protocolData replaceBytesInRange:NSMakeRange(_protocolLayout.one_offset, _protocolLayout.one_len) withBytes:&tempOne length:_protocolLayout.one_len];
  }
}
//two的设置 unsigned short
-(void)setTwo:(int)two{
  if (_protocolData.length !=_protocolSize) {
    //two为unsigned short 类型,所以要进行网络主机的传输字节顺序的转换 htons ->short 类型的主机存储->网络的网络存储,并写入内存块
    unsigned short tempTwo = two;
    tempTwo = htons(tempTwo);
    [_protocolData replaceBytesInRange:NSMakeRange(_protocolLayout.two_offset, _protocolLayout.two_len) withBytes:&tempTwo length:_protocolLayout.two_len];
  }
}
//three的设置 int
-(void)setThree:(int)three{
  if (_protocolData.length !=_protocolSize) {
    //three 为int类型 所以要进行网络主机的传输字节顺序的转换 htonl ->short 类型的主机存储->网络的网络存储,并写入内存块
    unsigned int tempThree = three;
    tempThree = htonl(tempThree);
    [_protocolData replaceBytesInRange:NSMakeRange(_protocolLayout.three_offset, _protocolLayout.three_len) withBytes:&tempThree length:_protocolLayout.three_len];
  }
}
//four的设置 string
-(void)setFour:(NSString *)four{
  if (_protocolData.length !=_protocolSize) {
    //four为字符串不需要进行存储转换
    NSData *tempFour = [four dataUsingEncoding:NSUTF8StringEncoding];
    [_protocolData replaceBytesInRange:NSMakeRange(_protocolLayout.four_offset, _protocolLayout.four_len) withBytes:tempFour.bytes length:_protocolLayout.four_len];
  }
}
//get one
-(int)getOne{
  if (_protocolData.length !=_protocolSize) {
    unsigned char temp;
    [_protocolData getBytes:&temp range:NSMakeRange(_protocolLayout.one_offset, _protocolLayout.one_len)];
    return temp;
  }
  return 0;
}
//get two
-(int )getTwo{
  if (_protocolData.length !=_protocolSize) {
    unsigned short temp;
    [_protocolData getBytes:&temp range:NSMakeRange(_protocolLayout.two_offset, _protocolLayout.two_len)];
    //short网络存储转本地存储
    return ntohs(temp);
  }
  return 0;
}
//get three
-(int)getThree{
  if (_protocolData.length !=_protocolSize) {
    unsigned char temp;
    [_protocolData getBytes:&temp range:NSMakeRange(_protocolLayout.three_offset, _protocolLayout.three_len)];
    //int网络存储转本地存储
    return ntohl(temp);
  }
  return 0;
}
//get four
-(NSString *)getFour{
  if (_protocolData.length !=_protocolSize) {
    NSData *temp = [_protocolData subdataWithRange:NSMakeRange(_protocolLayout.four_offset, _protocolLayout.four_len)];
    NSString *tempStr = [[NSString alloc]initWithUTF8String:temp.bytes];
    return tempStr;
  }
  return nil;
}
-(NSMutableData *)getProtocolData{
  return _protocolData;
}
-(int)getProtocolSize{
  return _protocolSize;
}
+(int)getProtocolSize{
  return ProtocolSize;
}
@end

小结:面向对象的思想封装,使数据实体和对数据实体的操作相关连


0 0