1.什么是粘包?

  粘包通常出现在TCP的协议里面,对于UDP来说是不会出现粘包状况的,之所以出现这种状况的原因,涉及到一种名为Nagle的算法。

  Nagle算法通过减少必须发送的封包的数量,提高网络应用程序系统的效率,解决负载问题。通俗的讲,就是在发包的时候会建立一个缓存区,发送的数据都会先进入这个缓存区,当上一条数据的接收被确认或者到达最大等待时间之后,才会将缓存区的数据一块发送过去,如此反复。将小包进行整合,避免小包多次发送造成的传输速度慢等问题。

2.什么时候才需要处理粘包?

  理论上来讲,只要是基于TCP的socket链接,都需要处理粘包的情况。

  可能有些人在测试的时候并没有出现粘包的情况,认为并不需要对粘包进行处理,这种想法是错误的。

  首先,在测试的时候之所以没有出现粘包情况,极有可能是因为网络路由问题,导致TCP的MTU会有所变化,Internet上的标准MTU值为576,以太网MTU为1500。所以测试粘包一般以外网环境进行测试。

3.粘包解决方案

  由于Nagle算法已经成为了默认的执行方式,所以对于粘包,在Server端和Client端都需要解决粘包的问题,由于问题一致,所以解决方案也基本是通用的,只是相关语法需要变换一下。

  由于iOS的底层对于socket的封装并不是那么完善,使用的话还得采用C语言,因此使用了一个名为CocoaAsyncSocket的第三方,将C的socket封装成了适合OC面向对象的形式,github地址如下:https://github.com/robbiehanson/CocoaAsyncSocket

  导入成功后,正式开始处理粘包问题。

  首先,跟服务器确定数据头的问题,对于粘包,一般有两种解决方案,第一种就是服务器返回的字段中有可识别的头和尾,我们可以根据可识别的头和尾来拆包。第二种是服务器返回的数据只包含头,头里面有数据的长度,我们可以根据这个头包含的数据长度来进行拆包。本文采用的便是第二种方案。

  服务器返回的数据为data形式的数据,打印出来的数据如下:

<fefd00f9 7b22736e 223a342c 22766572 73696f6e 223a2231 2e30222c 226e6574 466c6167 223a312c 22636d64 54797065 223a312c 22706475 223a7b22 70647554 79706522 3a343039 382c2264 65764461 7461223a 5b7b2264 65764964 223a2231 32333435 36373822 2c226465 764e616d 65223a22 e59b9ee8 b7afe68e a7e588b6 222c2270 4964223a 22343039 3833222c 22706172 616d223a 5b7b2274 79706522 3a383232 372c2276 616c7565 223a317d 2c7b2274 79706522 3a383232 382c2276 616c7565 223a307d 2c7b2274 79706522 3a383232 392c2276 616c7565 223a317d 2c7b2274 79706522 3a383233 302c2276 616c7565 223a317d 5d7d5d7d 7d>

  其中fefd00f9为服务器返回的头,后面为具体的数据。其中fefd占两个字节,00f9占两个字节,fefd是固定的值不做任何处理,00f9就是数据的长度

  接下来,在链接成功之后,在回调方法里面创建一个缓存区

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
self.readBuf = [[NSMutableData alloc] init];
  NSLog(@"链接成功后的其他操作"); }

  然后在收到服务器发送的数据的时候,对这个数据进行处理

//服务器发送的数据
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
//将数据存入缓存区
[self.readBuf appendData:data]; //数据中前面有4个字节的头信息,其中前两位是固定的头长度(用处不大),后两位才是数据的长度。
//如果大于4个字节证明有消息,因为服务器只要发送数据,必定包含头
while (self.readBuf.length > ) { //将消息转化成byte,计算总长度 = 数据的内容长度 + 前面4个字节的头长度
Byte *bytes = (Byte *)[self.readBuf bytes];
NSUInteger allLength = (bytes[]<<) + bytes[] +; //缓存区的长度大于总长度,证明有完整的数据包在缓存区,然后进行处理
if (self.readBuf.length >= allLength) {
NSMutableData *msgData = [[self.readBuf subdataWithRange:NSMakeRange(, allLength)] mutableCopy];
//提取出前面4个字节的头内容,之所以提取出来,是因为在处理数据问题的时候,比如data转json的时候,头内容里面包含非法字符,会导致转化出来的json内容为空,所以要先去掉再处理数据问题
[msgData replaceBytesInRange:NSMakeRange(, ) withBytes:NULL length:]; NSLog(@"开始处理数据问题"); //处理完数据后将处理过的数据移出缓存区
_readBuf = [NSMutableData dataWithData:[_readBuf subdataWithRange:NSMakeRange(allLength, _readBuf.length - allLength)]];
}else{
//缓存区内数据包不是完整的,再次从服务器获取数据,中断while循环
[self.clientSocket readDataWithTimeout:- tag:];
break;
}
} //读取到服务端数据值后,能再次读取
[self.clientSocket readDataWithTimeout:- tag:];
}

  这样处理之后,可以将粘包问题解决

  

iOS 处理socket粘包问题的更多相关文章

  1. Socket粘包问题

    这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题,发现自己不是很清楚,所以查资料了解记录一下: 一两个简单概念长连接与短连接:1.长连接 Client方与Server方先建立通 ...

  2. C#下利用封包、拆包原理解决Socket粘包、半包问题(新手篇)

    介于网络上充斥着大量的含糊其辞的Socket初级教程,扰乱着新手的学习方向,我来扼要的教一下新手应该怎么合理的处理Socket这个玩意儿. 一般来说,教你C#下Socket编程的老师,很少会教你如何解 ...

  3. [转]关于Socket粘包问题

    这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题,发现自己不是很清楚,所以查资料了解记录一下: 一两个简单概念长连接与短连接:1.长连接 Client方与Server方先建立通 ...

  4. 解决Socket粘包问题——C#代码

    解决Socket粘包问题——C#代码 前天晚上,曾经的一个同事问我socket发送消息如果太频繁接收方就会有消息重叠,因为当时在外面,没有多加思考 第一反应还以为是多线程导致的数据不同步导致的,让他加 ...

  5. Python socket粘包解决

    socket粘包: socket 交互send时,连续处理多个send时会出现粘包,soket会把两条send作为一条send强制发送,会粘在一起. send发送会根据recv定义的数值发送一个固定的 ...

  6. TCP Socket 粘包

     这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题.发现自己不是非常清楚,所以查资料了解记录一下: 一两个简单概念长连接与短连接: 1.长连接 Client方与Server ...

  7. socket粘包现象加解决办法

    socket粘包现象分析与解决方案 简单远程执行命令程序开发(内容回顾) res = subprocess.Popen(cmd.decode('utf-8'),shell=True,stderr=su ...

  8. 百万年薪python之路 -- socket粘包问题解决

    socket粘包问题解决 1. 高大上版解决粘包方式(自定制包头) 整体的流程解释 整个流程的大致解释: 我们可以把报头做成字典,字典里包含将要发送的真实数据的描述信息(大小啊之类的),然后json序 ...

  9. Socket粘包问题终极解决方案—Netty版(2W字)!

    上一篇我们讲了<Socket粘包问题的3种解决方案>,但没想到评论区竟然炸了.介于大家的热情讨论,以及不同的反馈意见,本文就来做一个扩展和延伸,试图找到问题的最优解,以及消息通讯的最优解决 ...

随机推荐

  1. python核心编程一书笔记之第一篇

    #!/usr/bin/env python# -*- coding:utf-8 -*- #env 是一个命令用来寻找系统中的python解释器.第二条解释使用utf-8编码 在类unix系统中允许py ...

  2. SpringMVC的流程分析(一)—— 整体流程概括

    SpringMVC的整体概括 之前也写过springmvc的流程分析,只是当时理解的还不透彻所以那篇文章就放弃了,现在比之前好了些,想着写下来分享下,也能增强记忆,也希望可以帮助到人,如果文章中有什么 ...

  3. 项目swift的一些问题

    在用swift做项目的时候,总会把之前oc的思想转过来. 1. 对Alamofire的再次封装,之前使用AFNetwork进行了在次封装,这样做的好处就是可以用一个全局的类来管理全部的网络请求,这样就 ...

  4. 《mysql必知必会》读书笔记--安全管理及数据库维护

    安全管理 mysql自带的mysql数据库中的user表可查看用户所有资料 创建用户帐号 CREATE USER ben IDENTIFIED BY 'p@$$wOrd' 重命名用户帐号 RENAME ...

  5. C#第二篇——关于C#中的正则表达式

    在C#中,正则表达式是用来进行查询在给出的一串字符中的某些字符或者数字的工具.与在办公软件中的查找功能相似,可以用精确查找也可以用模糊查找. 元字符: 元字符 说明 . 匹配除换行符以外的任意字符 \ ...

  6. Android 开发笔记___登陆app

    package com.example.alimjan.hello_world; /** * Created by alimjan on 7/4/2017. */ import android.con ...

  7. 逻辑卷lvm创建、扩展、缩小

    系统环境:CentOS Linux release 7.3.1611 (Core) 3.10.0-514.el7.x86_64 CentOS6与7配置方法大同小异.通常是在系统安装的时候创建lvm,然 ...

  8. BZOJ-2330-[SCOI2011]糖果(差分约束)

    Description 幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果.但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的 ...

  9. scrapy爬虫框架之理解篇(个人理解)

    提问: 为什么使用scrapy框架来写爬虫 ?            在python爬虫中:requests  +  selenium  可以解决目前90%的爬虫需求,难道scrapy 是解决剩下的1 ...

  10. HDU3045 Picnic Cows (斜率DP优化)(数形结合)

    转自PomeCat: "DP的斜率优化--对不必要的状态量进行抛弃,对不优的状态量进行搁置,使得在常数时间内找到最优解成为可能.斜率优化依靠的是数形结合的思想,通过将每个阶段和状态的答案反映 ...