粘包和拆包
/**

    tcp通信必然伴随着粘包或者拆包的情况.而每次通过didReadData这个委托方法收到的是数据都是以包为单位.拆包粘包说白了就是服务器一次给你发了很多条信息,但是这些信息不是一条信息一个包,而是一条信息分了几个包发来,或者几条信息的数据合到一个包发来了.

   java貌似自己有框架,闭着眼就能完成拆包合包的工作.但是oc上貌似没找到.只好手动.那首先要跟服务器有个协议,说明一下以什么作为一条信息的节点.比如我们,每条信息的头四个字节是用来保存这条信息的应有长度的.接到信息首先要读取长度,然后再跟收到的数据包长度对比.如果收到的长度刚刚好,说明这是一条完整的信息,直接封起来就行.如果收到的长度比预计长度短,说明信息被拆包发送,那就要继续跟下一个包进行拼装,再检验长度.如果收到的长度比预计的长,说明发生了粘包,那就要根据预计长度对数据包的数据进行拆分,对拆出的两部分数据继续进行处理.
 *  处理_bufferData
 *  主要处理拆包粘包问题.获得每段数据的长度之后,和当前buffer比较,如果刚好说明接收完全;如果buffer过大说明服务端粘包,需要拆包;如果buffer小说明服务端拆包,需要合包
 *
 *  @param newData 获取的新数据,如果只是本地拆包则传nil
 */
- (void)handleBufferData:(NSData *)newData
{
    if (newData)
    {
        //这是一个缓冲区,因为是全局的,并且是单例中,所以在数据取走的时候一定要清空
        [_bufferData appendData:newData];
    }
    
    //首先取前四位
    int i = 0;
    [_bufferData getBytes:&i range:NSMakeRange(0, 4)];
    //因为oc和java字节数组的高地位顺序是反的,所以要翻转一下顺序
    Byte *fix = [self overturnIntByteArr:i];
    memcpy(&i, fix, 4);
    free(fix);

    //刚好
    if (i == [_bufferData length]-4)
    {
        NSData *contentData = [_bufferData subdataWithRange:NSMakeRange(4, i)];
        //完整接收了一条信息的处理
        [self finishGetWholeData:contentData];
        
        _bufferData = [NSMutableData data];
    }
    //需要拆包
    else if (i < [_bufferData length]-4)
    {
        NSData *contentData = [_bufferData subdataWithRange:NSMakeRange(4, i)];
        //这是完成了第一个包的数据的接收
        [self finishGetWholeData:contentData];
        
        NSData *buffer = [_bufferData subdataWithRange:NSMakeRange(i+4, _bufferData.length-i-4)];
        _bufferData = [NSMutableData data];
        [_bufferData appendData:buffer];
        
        //继续进行判断处理
        [self handleBufferData:nil];
    }
}

 

posted on 2015-08-19 11:12  pTrack  阅读(1943)  评论(0)    收藏  举报