美文网首页
iOS:GCDAsyncSocket 的二次封装,粘包处理

iOS:GCDAsyncSocket 的二次封装,粘包处理

作者: 小刘_假装是个程序员 | 来源:发表于2018-03-15 18:09 被阅读0次

转载:http://blog.csdn.net/sdsd13212/article/details/64464232

因为要做实时数据所以简单的了解了下CocoaAsyncSocket这个库,其中的GCDAsyncSocket就是这个TCP协议通信的,看了一些网上demo之后基于目前使用的自定义协议的版本做了简单封装。

image

这是自定以的协议头,后面拼接了一个json包(目前改为了protobuf,因为这个确实比较好用,体积也小),后面的封装基于这个协议,可供大家做一个参考!!!!

#import <Foundation/Foundation.h>  
  
typedef void(^recive_Success_Block)(NSString *data,NSString *type);  
  
@interface HTAsyncSocket : NSObject  
  
//sockct  
@property(nonatomic,strong)GCDAsyncSocket* socket;  
  
//链接服务器  
- (BOOL)connecteServerWith:(NSString *)host onPort:(uint16_t )port;  
  
//断开服务器  
+ (void)disconnect;  
  
//发送数据  
- (void)sendDataWithType:(int)type withDic:(NSMutableDictionary *)dic ;  
  
//回调数据  
- (void) reciveData:(recive_Success_Block)reciveBlock;  
  
  
//拆包的到lenght  
+ (NSInteger)unpackingLenght:(NSString *) packing;  
  
//拆包的到type  
+ (NSString *)unpackingHeard:(NSString *)packing;  
  
//拆包的到json  
+ (NSDictionary *)unpackingDicWith:(NSString *) packing;  
  
//拆包的到NSMutableArray  
+ (NSMutableArray *) unpackingArrWith:(NSString *)packing WithHeard:(NSString *)str;  
  
//单例  
+(instancetype) shareAsncSocket;  
#import "HTAsyncSocket.h"  
  
@interface HTAsyncSocket()<GCDAsyncSocketDelegate>  
//定时器  
@property(nonatomic,strong)NSTimer* connectTimer;  
  
//接收成功的回调  
@property(nonatomic,copy) recive_Success_Block reciveBlock;  
  
//接收完整的包  
@property(nonatomic,strong)NSMutableData* completeData;  
  
//完整包的长度  
@property(nonatomic,assign)NSInteger lenght;  
  
//发送心跳包的线程  
@property (nonatomic, strong)NSThread *thread;  
  
@end  
  
@implementation HTAsyncSocket  
  
//链接服务器  
- (BOOL) connecteServerWith:(NSString *)host  onPort:(uint16_t)port{  
    static BOOL success;  
    GCDAsyncSocket *sockte =  [HTAsyncSocket shareAsncSocket].socket;  
    if (!sockte.isConnected) {  
        NSError *err;  
        success = [sockte connectToHost:host onPort:port error:&err];  
        if (err != nil)  
        {  
            NSLog(@"%@",err);  
        }  
    }  
    return success;  
}  
  
//链接成功  
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{  
    NSLog(@"交易链接成功");  
  
    [_socket readDataWithTimeout:-1 tag:0];   
      
    //开始发送心跳包  
    [self.thread start];  
}  
  
  
//心跳包发送  
- (void)threadStart{  
    @autoreleasepool {  
        [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(heartBeat) userInfo:nil repeats:YES];  
        [[NSRunLoop currentRunLoop]run];  
    }  
}  
  
- (void)heartBeat{  
    NSString *str = @"心跳包内容";  
    NSData *ndata = [str dataUsingEncoding:NSUTF8StringEncoding];  
    [self.socket writeData:ndata withTimeout:-1 tag:1];  
}  
  
//socket断开  
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(nullable NSError *)err{  
    NSLog(@"交易服务器断开%@",err);  
}  
  
  
//断开服务器  
+ (void)disconnect{  
    //断开连接时候一定要清空socket  
    GCDAsyncSocket *sockte =  [HTAsyncSocket shareAsncSocket].socket;  
      
    [sockte disconnect];  
      
    sockte = nil;  
}  
  
//接收信息  
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{  
      
    [self.completeData appendData:data];  
    NSString *msg = [[NSString alloc] initWithData:self.completeData encoding:NSUTF8StringEncoding];  
    self.lenght = [HTAsyncSocket unpackingLenght:msg];  
    //这里因为有时候会粘包,所以等长度一致,拼接完整之后再发送数据出去  
//    NSLog(@"self.completeData.length-%ld  self.lenght-%ld",self.completeData.length ,self.lenght);  
    if (self.completeData.length >= self.lenght) {  
        NSString *type = [HTAsyncSocket unpackingHeard:msg];  
        if (_reciveBlock ) {  
//            NSLog(@"tmsg = %@ ", msg);  
            _reciveBlock(msg,type);  
        }  
        self.completeData = 0;  
        self.lenght = 0;  
    }  
    [self.socket readDataWithTimeout: -1 tag:0];  
}  
  
//发送数据  
- (void)sendDataWithType:(int)type withDic:(NSMutableDictionary *)dic {  
    NSData *data=[NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];  
    NSString *json=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];  
      
    NSString *lenght = [NSString stringWithFormat:@"%ld",json.length];  
    int num = [lenght intValue]+37;  
      
    lenght = [self num:num];  
    NSString *stype = [self num:type];  
  
    NSString *header= [NSString stringWithFormat:@"V0.1%@%@00000000000000000",lenght,stype];  
    NSString *package = [NSString stringWithFormat:@"%@%@",header,json];  
    NSLog(@"package-%@",package);  
    NSData *ndata = [package dataUsingEncoding:NSUTF8StringEncoding];  
      
    [self.socket writeData:ndata withTimeout:-1 tag:1];  
      
}  
  
//接收数据  
- (void) reciveData:(recive_Success_Block)reciveBlock {  
   _reciveBlock = reciveBlock;  
}  
  
- (NSString *)num:(int) num{  
    NSString *str = [NSString stringWithFormat:@"%d",num];  
    int sum = 0 ;  
    while(num!=0){  
        num /= 10;  
        sum++;  
    }  
    for (int i = sum ; i < 8 ; i ++) {  
        str = [NSString stringWithFormat:@"0%@",str];  
    }  
    return str;  
}  
  
  
//拆分出长度  
+ (NSInteger)unpackingLenght:(NSString *) packing{  
    if (!packing ) return 0;  
    NSRange range =  NSMakeRange (0, 37);  
    NSString *heard = [packing substringWithRange:range];  
      
    NSRange sRange = NSMakeRange(4, 8);  
    NSString *lenght = [heard substringWithRange:sRange];  
      
    NSInteger slenght = [lenght integerValue];  
    return slenght;  
}  
  
//拆分出类型  
+ (NSString *)unpackingHeard:(NSString *)packing{  
    if (!packing ) return nil;  
    NSRange range =  NSMakeRange (0, 37);  
    NSString *heard = [packing substringWithRange:range];  
      
    NSRange sRange = NSMakeRange(12, 8);  
    NSString *type = [heard substringWithRange:sRange];  
      
    return type;  
}  
  
//NSDictionary拆包  
+ (NSDictionary *)unpackingDicWith:(NSString *) packing{  
      
    if (!packing ) return nil;  
      
    NSRange rjson = NSMakeRange(37, packing.length - 37);  
    NSString *json = [packing substringWithRange:rjson];  
      
    NSData *jsonData = [json dataUsingEncoding:NSUTF8StringEncoding];  
      
    NSError *err;  
    NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData  
                                                        options:NSJSONReadingMutableContainers  
                                                        error:&err];  
      
    return dic;  
}  
  
//NSMutableArray拆包  
+ (NSMutableArray *) unpackingArrWith:(NSString *)packing WithHeard:(NSString *)str{  
  
    if (!packing ) return nil;  
      
    NSRange rjson = NSMakeRange(37, packing.length - 37);  
    NSString *json = [packing substringWithRange:rjson];  
      
    NSData *jsonData = [json dataUsingEncoding:NSUTF8StringEncoding];  
      
    NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData  
                                                        options:NSJSONReadingMutableContainers  
                                                        error:nil];  
      
    NSMutableArray *array = dic[str];  
      
    return array;  
      
      
}  
  
//发送成功  
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{  
    NSLog(@"交易发送成功");   
    [_socket readDataWithTimeout:-1 tag:0];  
}  
  
//全局唯一  
- (GCDAsyncSocket *)socket{  
    if (!_socket) {  
        _socket = [[GCDAsyncSocket alloc]   
                   initWithDelegate:self   
                   delegateQueue:dispatch_get_main_queue()];  
    }  
    return _socket;  
}  
  
  
- (NSMutableData *)completeData{  
    if (!_completeData ) {  
        _completeData = [[NSMutableData alloc]init];  
    }  
    return _completeData;  
}  
  
- (NSInteger)lenght{  
    if (!_lenght) {  
        _lenght = 0 ;  
    }  
    return _lenght;  
}  
  
- (NSThread*)thread{  
    if (!_thread) {  
        _thread = [[NSThread alloc]initWithTarget:self selector:@selector(threadStart) object:nil];  
    }  
    return _thread;  
}  
  
+(instancetype) shareAsncSocket{  
    static id _instance;  
    static dispatch_once_t _onceToken;  
    dispatch_once(&_onceToken, ^{  
        _instance = [[self alloc]init];  
    });  
    return _instance;  
}  

//调用的时候也很简单

//请求登陆  
HTAsyncSocket *socket = [HTAsyncSocket shareAsncSocket];  
[socket sendDataWithType:功能号   
                 withDic:发送的数据];  
[socket reciveData:^(NSString  *data, NSString *type) {  
}];

相关文章

网友评论

      本文标题:iOS:GCDAsyncSocket 的二次封装,粘包处理

      本文链接:https://www.haomeiwen.com/subject/qgohqftx.html