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

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

时间: 2024-11-06 07:35:21

iOS-二进制协议的封装的相关文章

轻量级通信引擎StriveEngine —— C/S通信demo(2) —— 使用二进制协议 (附源码)

在网络上,交互的双方基于TCP或UDP进行通信,通信协议的格式通常分为两类:文本消息.二进制消息. 文本协议相对简单,通常使用一个特殊的标记符作为一个消息的结束. 二进制协议,通常是由消息头(Header)和消息体(Body)构成的,消息头的长度固定,而且,通过解析消息头,可以知道消息体的长度.如此,我们便可以从网络流中解析出一个个完整的二进制消息. 两种类型的协议格式各有优劣:文本协议直观.容易理解,但是在文本消息中很难嵌入二进制数据,比如嵌入一张图片:而二进制协议的优缺点刚刚相反. 在 轻量

iOS xmpp协议实现聊天之openfire的服务端配置(一)

今天弄这个openfire服务端的配置直接苦了一逼,不过好在最后终于配置好了.首先感谢@月光的尽头的博客给了我莫大的帮助.切入正题,首先说一下iOS xmpp协议实现聊天openfire服务器配置所需要的东西: 1.openfire软件,我用的是 Openfire 3.9.3,下载地址:http://www.igniterealtime.org/downloads/index.jsp 2.MySql数据库,我用的是mysql-5.1.63,下载地址:http://dev.mysql.com/do

Memcached 二进制协议(BinaryProtocol) incr指令泄露内存数据的bug

缘起 最近有个分布式限速的需求.支付宝的接口双11只允许每秒调用10次. 单机的限速,自然是用google guava的RateLimiter. http://docs.guava-libraries.googlecode.com/git-history/master/javadoc/com/google/common/util/concurrent/RateLimiter.html 分布式的ReteLimiter,貌似没有现在的实现方案.不过用memcached或者Redis来实现一个简单的也

iOS Http协议与TCP协议简单理解

在C#编写代码,很多时候会遇到Http协议或者TCP协议,这里做一个简单的理解. TCP协议对应于传输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性.Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求.Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的.所以Http连接是一种短连接,是一种无状态的连接.所谓的无状态,是指浏览器每次向服务器发起请求的时候,

一种通用的树形二进制协议描述方法与处理算法

概述: 本方法定义了一种数据结构,可用于描述任意的树形二进制协议,并配合一个特定的处理算法,可实现一种通用的,由该种树形二进制协议定义的比特流解析与填充的处理,该数据结构的定义如下: /* 以下结构用于定义一个协议节点的描述信息. */ struct _proto_info; typedef struct _proto_des { const char *              name; /* 用于描述一个协议节点的名称. */ size_t                    stat

iOS xmpp协议实现聊天之openfire的服务端配置(二)

本篇主要说一下如何利用命令行来正确配置MySql. 首先打开终端: 1.为mysql起一个别名 alias mysql=/usr/local/mysql/bin/mysql 2.创建mysql的管理员  admin(后期登陆用到) alias mysqladmin=/usr/local/mysql/bin/mysqladmin 3.设置root账号密码 mysqladmin -u root password 初始密码 4.连接数据库 mysql -u root -p  (提示输入刚才的密码) 5

文本协议与二进制协议的选择

进行网络通信时,我们经常纠结于到底使用什么样的协议传输数据,下面我谈谈应该怎么选择一种合理的协议格式. 网络协议 标准定义是这样的: 为计算机网络中进行数据交换而建立的规则.标准或约定的集合. 网络协议至少包括三要素: 语法:语法是用户数据与控制信息的结构与格式,以及数据出现的顺序. 语义:解释控制信息每个部分的意义.它规定了需要发出何种控制信息,以及完成的动作与做出什么样的响应. 时序:时序是对事件发生顺序的详细说明. 人们形象地把这三个要素描述为:语义表示要做什么,语法表示要怎么做,时序表示

调用Live555接收RTSP直播流,转换为Http Live Streaming(iOS直播)协议

Live555接收RTSP直播流,转换Http Live Streaming(iOS直播)协议 RTSP协议也是广泛使用的直播/点播流媒体协议,之前实现过一个通过live555接收RTSP协议,然后转换为HLS(Http Live Streaming)直播协议文件的程序,为的是可以接收远端设备或服务器的多路RTSP直播数据,实时转换为HLS协议文件,以实现iPhone或iPad等设备观看RTSP直播源的需求.现在把实现的思路分享如下. 要点分析 首先,程序的主要目的,是从多路RTSP输入源中提取

ios sqlite3数据库的封装-自己封装的,针对锁死database is closed的解决和预防

在数据库创建时应判断数据是否存在(不为空nil) if(sqlite==nil){// 判断数据库是否存在,若存在就不创建,若不存在才创建,以防数据库锁死 if (SQLITE_OK == sqlite3_open(dpPath.UTF8String , &sqlite)) { NSLog(@"数据库创建成功"); }else{ NSLog(@"数据库创建失败"); } } #import "SqlManager.h" #import &