iOS 处理socket粘包问题
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粘包问题的更多相关文章
- Socket粘包问题
这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题,发现自己不是很清楚,所以查资料了解记录一下: 一两个简单概念长连接与短连接:1.长连接 Client方与Server方先建立通 ...
- C#下利用封包、拆包原理解决Socket粘包、半包问题(新手篇)
介于网络上充斥着大量的含糊其辞的Socket初级教程,扰乱着新手的学习方向,我来扼要的教一下新手应该怎么合理的处理Socket这个玩意儿. 一般来说,教你C#下Socket编程的老师,很少会教你如何解 ...
- [转]关于Socket粘包问题
这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题,发现自己不是很清楚,所以查资料了解记录一下: 一两个简单概念长连接与短连接:1.长连接 Client方与Server方先建立通 ...
- 解决Socket粘包问题——C#代码
解决Socket粘包问题——C#代码 前天晚上,曾经的一个同事问我socket发送消息如果太频繁接收方就会有消息重叠,因为当时在外面,没有多加思考 第一反应还以为是多线程导致的数据不同步导致的,让他加 ...
- Python socket粘包解决
socket粘包: socket 交互send时,连续处理多个send时会出现粘包,soket会把两条send作为一条send强制发送,会粘在一起. send发送会根据recv定义的数值发送一个固定的 ...
- TCP Socket 粘包
这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题.发现自己不是非常清楚,所以查资料了解记录一下: 一两个简单概念长连接与短连接: 1.长连接 Client方与Server ...
- socket粘包现象加解决办法
socket粘包现象分析与解决方案 简单远程执行命令程序开发(内容回顾) res = subprocess.Popen(cmd.decode('utf-8'),shell=True,stderr=su ...
- 百万年薪python之路 -- socket粘包问题解决
socket粘包问题解决 1. 高大上版解决粘包方式(自定制包头) 整体的流程解释 整个流程的大致解释: 我们可以把报头做成字典,字典里包含将要发送的真实数据的描述信息(大小啊之类的),然后json序 ...
- Socket粘包问题终极解决方案—Netty版(2W字)!
上一篇我们讲了<Socket粘包问题的3种解决方案>,但没想到评论区竟然炸了.介于大家的热情讨论,以及不同的反馈意见,本文就来做一个扩展和延伸,试图找到问题的最优解,以及消息通讯的最优解决 ...
随机推荐
- Vue源码后记-vFor列表渲染(1)
钩子函数比较简单,没有什么意思,这一节搞点大事情 => 源码中v-for的渲染过程. vue的内置指令包含了v-html.v-if.v-once.v-bind.v-on.v-show等,先从一个 ...
- Python 爬虫:把廖雪峰教程转换成 PDF 电子书
写爬虫似乎没有比用 Python 更合适了,Python 社区提供的爬虫工具多得让你眼花缭乱,各种拿来就可以直接用的 library 分分钟就可以写出一个爬虫出来,今天尝试写一个爬虫,将廖雪峰老师的 ...
- Red and Black
Problem Description There is a rectangular room, covered with square tiles. Each tile is colored eit ...
- Intervals
Intervals Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Su ...
- hdu 1520 Anniversary party(入门树形DP)
Anniversary party Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 6926 Accepted: 3985 ...
- JAVAscript学习笔记 jsBOM 第七节 (原创) 参考js使用表
<html> <head> <title>day02_js</title> <script type="text/javascript& ...
- Fiddler手机抓包图文教程
上篇Fiddler教程,我们教了大家Fiddler安装配置及如何使用Fiddler进行基本的Http抓包及模拟请求,今天给大家介绍下如何使用Fiddler进行手机抓包. 运行环境为Windows 10 ...
- Ubuntu 12.04嵌入式交叉编译环境arm-linux-gcc搭建过程
Ubuntu 12.04嵌入式交叉编译环境arm-linux-gcc搭建过程Linux版本:Ubuntu 12.04 内核版本:Linux 3.5.0 交叉编译器版本:arm-linux-gcc-4. ...
- Datatbel和 string之间的相互转换
Datatable 到 string public static string DataTableToString(DataTable dt) { //!@&am ...
- ImageMagick图片服务器
1.前置准备工具如下: nodejs express(nodejs mvc框架) body-parser(express middleware) gm(nodejs中用来处理图片的) uuid(nod ...