iOS之Protobuf拆包和粘包问题处理

在上一篇文章《iOS之ProtocolBuffer搭建和示例demo》分享环境的搭建, 我们和服务器进行IM通讯用了github有名的框架CocoaAsynSocket, 然后和服务器之间的数据媒介是ProtoBuf。然后后面在开发的过程中也碰到了拆包和粘包问题,这方面网上资料很少,曲折了一下才解决,这里分享一下问题的解决过程!

首先描述下碰到的问题:

1、服务器发送内容很长的数据过来的时候,GCDAsyncSocket监听收到的一个包解析不了,一直要接收好几个包拼接才是这条数据的完整包,即所谓的拆包;

2、服务器快速发送多条数据过来,传到客户端这边的时候几条数据合成了一个包,即所谓的粘包。所以想解析这些粘在一起的数据,必须知道每条数据的长度,才能正确切割解析。

先上关键代码,解决读取每条数据的头部字节,根据头部字节读取这条数据的内容长度。这样才能完美的解决粘包问题。由于根据数据的长度不一样,导致头部字节占用的长度也会不一样,比如说我这里反复测试的结果头部占用字节一般为1和2,短内容数据头部占用字节长度为1,长内容数据头部占用字节长度为2。这里的代码参考了谷歌提供的Protobuf的objectivec版的源码。

关键代码,读取每条数据的头部占用字节,和内容长度:

/**获取data数据的内容长度和头部长度: index -->头部占用长度(头部占用长度1-4个字节) */

- (int32_t)getContentLength:(NSData *)data withHeadLength:(int32_t *)index{

       int8_t tmp = [self readRawByte:data headIndex:index];

      if(tmp >=0) return tmp;

      int32_t result = tmp & 0x7f;

      if((tmp = [self readRawByte:data headIndex:index]) >=0) {

         result  |= tmp << 7;

      }else{

         result  |= (tmp & 0x7f) << 7;

        if((tmp = [self readRawByte:data headIndex:index]) >=0) {

           result  |= tmp << 14;

        }else{

          result  |= (tmp & 0x7f) << 14;

         if((tmp = [self readRawByte:data headIndex:index]) >=0) {

            result  |= tmp << 21;

        }else{

          result  |= (tmp & 0x7f) << 21;

         result  |= (tmp = [self readRawByte:data headIndex:index]) << 28;

        if(tmp <0) {

           for(inti =0; i <5; i++) {

               if([self readRawByte:data headIndex:index] >=0 ) {

                   return result;

                }

          }

          result = -1;

     }

   }

  }

  }  

return result;

}

/**读取字节*/

- (int8_t)readRawByte:(NSData *)data headIndex:(int32_t *)index{

   if(*index >= data.length) return -1;

  *index = *index +1;

 return ((int8_t *)data.bytes)[*index -1];

}


原文链接见:CocoaAsyncSocket + Protobuf 处理粘包和拆包问题

demo链接:https://github.com/xiaotanit/Tan_ProtocolBuffer

你可能感兴趣的:(iOS之Protobuf拆包和粘包问题处理)