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