【Android学习】socket长连接,数据粘包问题

1,问题再现

之前的socket连接,都是每次使用的时候,重新new socket。根据实际需求,需要进行长连接,即:socket连接后不断开,每次使用的时候也不重新new新的socket。此时出现新的问题:第一次发送数据还好,第二次接收到的数据出现粘包问题,导致json解析数据无法成功。

2,问题解决

上网搜了无数帖子,发现socket的粘包问题始终无法避免。最后我们采用了http来进行登录、任务的接收。总算是完成了业务需求。但是就学习而言,socket的粘包问题并没有解决,只是绕过了问题。

我试过很多方法,如,通过方法关闭Nagle算法:socket.setTcpNoDelay(true);并不可行。希望以后继续研究。

3,概念

1)长连接

Client方与Server方先建立通讯连接,连接建立后不断开, 然后再进行报文发送和接收。

2)短连接

Client方与Server每进行一次报文收发交易时才进行通讯连接,交易完毕后立即断开连接。此种方式常用于一点对多点通讯,比如多个Client连接一个Server。

HTTP采用无状态的短连接的通信方式,一次请求完成一次数据交互,然后断开连接。短链接能够 同时服务更多的用户,所以不可能每个用户访问一次后就一直保持这个链接。

4,粘包原因

1)TCP协议无包边界

①TCP短连接

如果利用tcp每次发送数据,就与对方建立连接,然后双方发送完一段数据后,就关闭连接(双方都发送close连接),这样就不会出现粘包问题(因为只有一种包结构,类似于http协议)。

②TCP长连接:

在连接后一段时间发送很多数据,而这些数据结构不同,就可能造成粘包问题。对于解决办法,一般是在头加一个数据长度之类的包,以确保接收。
而如果接收方不及时接收缓冲区的包,也会造成多个包接收,造成粘包问题。

③包边界:

UDP有包边界,应用层要整包地收,一次只能收一包,每次接收的要么是一个独立的完整的数据包,要么什么也接收不到。
而TCP是无边界的,是字节流,需要应用层自己判断包边界,一次不一定能收几包,也不一定是完整的包。
所以TCP会造成粘包,而UDP不会造成粘包问题。

④解决办法

a.发送固定长度的消息

缺少灵活性。

b.使用特殊标记分隔消息

需要处理消息内容。太复杂,不实用。
通过正则表达式解决数据传输过程中的堆包问题

c.定制协议

安全但开销大。
固定位填写消息长度,将消息长度和消息一起发送。

规定了包传送的格式。协议里规定每包传送的字节数,对于格式不正确的错误数据进行丢弃处理并清空接收的缓冲区。

2)缓冲区工作机制

①对于发送方

为了提高效率,发送方要等到发送缓冲区满,才会把TCP报文段发送出去,接收方同样也是等缓冲区满了才读取数据。

②对于接收方

由于TCP是接收到包头信息后,再接收包数据,再接收数据时,对于Buffer的设置很难抉择。
首先,如果接收Buffer过小,TCP将返回实际接收的长度,余下的还可以继续接收。

这样,造就的问题就是:
当Buffer佷大,那么可能收到的就是多个发包,你必须分离它们。
当Buffer太小,而一次收不完Socket内部的数据,那么Socket接收事件(OnReceive),可能不会再触发。

而我们最后才用WCF,通过HTTP来传输数据,同样是因为HTTP封装之后有的包边界,且采用的是短连接,避免了粘包问题。

③解决方案

优化程序设计、精简接收进程工作量、提高接收进程优先级等措施,使其及时接收数据,从而尽量避免出现粘包现象。
但是当发送频率较高时,或由于网络突发可能使某个时间段数据包到达接收方较快,接收方还是有可能来不及接收,从而导致粘包。如:网络状态差的情况下,很容易发生刚连接上网络一下子突然连接到多个包的情况。
由接收方控制,将一包数据按结构字段,人为控制分多次接收,然后合并,通过这种手段来避免粘包。
但是,这样应用程序的效率较低,对实时应用的场合可能不适合。

3)发送方分段或合并数据发送

①问题

TCP是面向连接的网络通信协议,为了增强网络数据传输的效率就要避免一个很小的数据多次发送所带来的开销。因此,TCP在数据发送端等待接受到足够多的数据后才打包发送一包数据。如果数据发送端连续多次发送较少的数据量,一般情况下TCP会自动根据Nagle算法把发送端这些较小的数据集合打包在一起,直到集合在一起的数据量足够大,然后把集合到一起的数据发送出去。这样就造就了接收端收到的数据粘在一起。

造成数据包截断的原因一般是通信过程中出现网络故障,导致本来完整的数据包被分割成多个小的数据包发送到接收端,接收端收到的数据不能够组成一个完整的数据包。

②解决方案

关闭Nagle算法。
通过方法:socket.setTcpNoDelay(true);并不可行。希望以后继续研究。

4)粘包情况

①完整的数据包粘在一起

②粘在一起的数据包存在不完整的数据包

产生了数据截断。
处理方式:取走完整的数据包,把不完整的数据包留在缓冲区中,继续等待下一部分数据包的到来。

5,何时不需要考虑粘包?

如果发送的数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值