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