socket,如果是做tcp连接,可能会遇到粘包与半包的问题,TCP属于传输层的协议,传输层除了有TCP协议外还有UDP协议。那么UDP是否会发生粘包或拆包的现象呢?答案是不会。UDP是基于报文发送的,从UDP的帧结构可以看出,在UDP首部采用了16bit来指示UDP数据报文的长度,因此在应用层能很好的将不同的数据报文区分开,从而避免粘包和拆包的问题。而TCP是基于字节流的,虽然应用层和TCP传输层之间的数据交互是大小不等的数据块,但是TCP把这些数据块仅仅看成一连串无结构的字节流,没有边界;另外从TCP的帧结构也可以看出,在TCP的首部没有表示数据长度的字段,在使用TCP传输数据时,才有粘包或者拆包现象发生的可能。粘包就是多组数据被一并接收了,粘在了一起,无法做划分;半包就是有数据接收不完整,无法处理。要解决粘包、半包的问题,一般在设计数据(消息)格式时会约定好一个字段专门用于描述数据包的长度,这样就使数据有了边界,依靠这个边界,就能把每组数据划分出来,数据不完整时也能获知数据的缺失。
封包
一般在使用Socket的时候,后台会对Socket传输数据有一个自定义的协议,协议可能有些差别不过基本上是大同小异。
Socket发送给服务器的数据,最终要转换成二进制流数据,并且按照协议约定的格式。
eg:消息=消息头+消息体。消息头用于描述消息本身的基本信息,消息体则为消息的具体内容
粘包、拆包
我们假设在主机A和主机B的应用程序之间有一条TCP连接,主机A有两条报文D1,D2要发送到B主机,并两次调用send来发送,每条报文调用一次。
那么,我们自然而然的希望两条报文是作为两个独立的实体,在各自的分组中发送
这样的话,我们无需做任何特别的处理,便能够很容易的区分每一个独立的数据,并根据需求分别做相应的处理。但现实往往是有所偏差的,实际的数据传输过程很可能不会遵循这个模型。而是会采用以下四种方式之一进行传输
实际上,可能的情况还不止4种,这里我们就不做深入了解,以上就是造成粘包的原因。
解决思路:拆包
在上面说到我们给每个数据包添加头部,头部中包含数据包的长度,这样接收到数据后,通过读取头部的长度字段,便知道每一个数据包的实际长度了,再根据长度去读取指定长度的数据便能获取到正确的数据了。
再来回顾一下 协议:
完整的数据包 = 服务号 + 数据包长度 + 数据
数据包头 = Id(4B) + length(4B) 共占用8字节
数据包 = length(假设占100个字节)
所以这条消息的长度就是108字节可以看到,要想知道一条完整数据的边界,关键就是数据包头中的length字段
iOS客户端就需要很好的第三方CocoaAsyncSocket来进行长连接连接和传输数据,该第三方地 址:https://github.com/robbiehanson/CocoaAsyncSocket,
iOS开发之Socket通信实战--Request请求数据包编码模块
补充博客:初用 CocoaAsyncSocket