iOS socket即时通讯粘包处理

iOS在做即时通讯类应用或游戏一般都是用sokect通讯,CFSocket是苹果提供给我们的使用Socket的方式,用起来比较麻烦,里面很多东西要自己处理。平时开发项目中首选 AsyncSocket 开源库,它帮助我们封装了很多东西。我们只需要 建立连接 设置代理、发送数据、接受数据,使用起来很方便。如果是tcp连接,那就不可避免的会遇到粘包与半包的问题。来看看如何处理:

在设计上,每一个包带上一个length的字段,表示包的长度。这样服务器、客户端才好处理粘包问题。客户端接受到数据先把这些数据放到缓冲区,根据length字段来取正确的长度,如果数据不够这个长度就等下一个数据的到来,如果还不够 继续...要是数据多于这个长度 我们只取length的长度,剩下的放缓冲区 这个肯定是下一个包的数据,同理处理。看代码:

1.我这里每个包前面都带了一个int型length,int型migid,


- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag

{

       NSLog(@"接受到消息");

       [self.socket readDataWithTimeout:-1 tag:0];

       //将接受到的数据data 保留到缓冲区_bufData

       [_bufData appendData:data];

       //拿到包长,缓冲区的前4个字节为包长

       int len ;

       [_bufData getBytes:&len range:NSMakeRange(0, 4)];

       //够一个包长的数据的话 就从缓冲区取出来,这样就能拿到一个正确完整的包,不够一个包长就等下一   次接收数据放于缓冲区

       while (len<= _bufData.length) {

              //得到每个包的数据

               NSData *tmp = [_bufData subdataWithRange:NSMakeRange(0, len)];

 //            NSData * sercetData = [self getSecret:[tmp mutableCopy] key:self.secretKey];

                int msgid;

                [tmp getBytes:&msgid range:NSMakeRange(4, 4)];

                NSLog(@"msgid:%d",msgid);

                if (msgid <= 0)  break;

               //转化 数据

                [[PGSocketTransmit share] transmitMessageWith:tmp];

              //取完这段数据,把缓冲区后面的数据移到最前面,保证每次取前4个字节 都是一个int类型的包长

              _bufData = [_bufData subdataWithRange:NSMakeRange(len, _bufData.length -len)].mutableCopy;

              //如果刚好取完,跳出循环

             if (_bufData.length == 0) {

                      break;

              }

              else{//得到下一个包的长度,继续判断

                    [_bufData getBytes:&len range:NSMakeRange(0, 4)];

               }

         }

}


2.数据传输一般是要求加密的,这里给出简单的 异或 加密,每一次连接服务器返回一个随机的int类型的key,用这个key跟发送的数据异或,当然服务器返回你的数据也是需要 用这个key异或处理的 才会得到正确的数据。把我们习惯的NSData转成byte,用指针 操作地址来处理,如下,向服务器发送数据NSdata 从服务器拿到数据NSdata 调这个方法 返回 异或 后的数据。

- (NSData *)getSecret:(NSMutableData*)data key:(int32_t)key{

      void* bytes = data.mutableBytes;

       int length = (int)data.length;

       for (int i = 0; i < length; i += 4) {

               int32_t value = *(int32_t*)(bytes + i);

               value ^= key;

               memcpy(bytes + i, &value, MIN(i + 4, length) - i);

       }

       return [[NSData alloc]initWithBytes:bytes length:length];

}

你可能感兴趣的:(iOS socket即时通讯粘包处理)