android客户端连接服务端
客户端使用nio长连接
在服务端主动断开连接时,出现了不停打印以下类似日志
03-07 19:21:49.562: D/dalvikvm(1677): GC_CONCURRENT freed 2859K, 20% free 12020K/15011K, paused 1ms+17ms
GC_CONCURRENT 原因 Triggered when the heap has reached a certain amount of objects to collect
在排查之下发现
int nKeys = selector.select(500);
//nKeys = 1
iterator = selector.selectedKeys().iterator();
key = iterator.next();
iterator.remove();
//key.isReadable()=true
ByteBuffer buffer = ByteBuffer.allocate(2048);
SocketChannel sc = (SocketChannel) key.channel();
int ret = sc.read(buffer)
//ret = -1
服务器未主动断开前,ret没数据时都返回0
当主动断开时,ret返回-1,selector.select(500) 会一直返回1.导致了内存问题,促发了gc
因此我在ret返回-1且buffer未读到任何数据时,来判断连接已经主动断开
在没有碰到手机 htc t328w之前。nio通讯一直正常
之后出现了一个现象
nio的 selector.select(500),时而正常,时而看似堵塞的现象,明明有数据发来,select函数始终返回0,而不报异常,堵塞个几分钟,10几分钟才会把之前的数据读到
由于测试过5,6个手机,都是正常的。这款手机让我纳闷了
开始怀疑是否系统问题,重新刷机,发现现象仍然任然存在
最后在
http://stackoverflow.com/questions/9939989/java-nio-selector-select-returns-0-although-channels-are-ready
找到了答案。我就是用的foreach循环来循环selectkeys。
改为iterator后正常
App与服务器的通信无非两种pull、push。后台消息的传递如果没有很强的实时性要求的话,pull还是比较实惠的。但对于实时性要求比较高的就需要用到push了。这篇文章主要分享一下push的流程、应用场景。
相比pull,push无论是在实现复杂度还是在成本上都要高很多。长连接的维持、心跳包的发送、服务器的压力、客户端的消耗、流量的控制都是需要一个个攻克的。笔者也是走在亦步亦趋的路上,分享一下自己的心得,还请多拍砖。
长连接是指在客户端和服务器维持一个不断的连接,这样服务器任何时候有消息需要发送的话都可以直接push给客户端。鉴于各个网关的特性,这个连接并不是真的不断,而是即使断了马上重连。
通常,一个长连接是这样开始的:
客户端向服务器发送一个要求keep-alive的连接请求,经过运营商的网关,到达自己的服务器,读取数据完毕后,不要关闭连接。网关为保持自己的瘦身,节省资源,会断掉一段时间内没有数据传递的连接。这个时间各地的网关不同,从1分钟到半小时都可能有。
我们为了让连接不断,就需要隔一段时间向服务器发送一个心跳包,网关看到我们传递数据了,就不会断掉我们的连接。心跳包的发送时间间隔可以动态调用适应当地的网关,达到维持长连接、节省流量、减少耗电的目的。
有这么几个因素可能会影响心跳质量。
A、用户机器休眠:我知道用户长时间不操作机器时,CPU会停掉的,如果我们的心跳时间小于机器休眠的timeout的话,机器就睡不下去了。而电,也很快就没了。
B、心跳包大小:要尽量小,那都是用户的钱。
C、动态适应算法:要在维持长连接满足业务要求的基础上尽量减少断掉重新连接的次数,要知道每次握手都是消耗很大的一件事情。
D、网关timeout:这个瓶颈主要在各地运营商的网关,没有固定的值,需要客户端自适应。
E、我们自己服务器的timeout。服务器端维持长连接不需要像客户端那么多的技巧,只需要CPU、内存、带宽这三大件。但这些也都是钱,还是以满足业务需求为准。另外,两个timeout中最小的那个就是我们维持长连接的心跳时间间隔,所以,服务器的timeout如果大于网关的timeout是完全没有意义的。
任何一项技术如果脱离了实际的应用场景来讨论是没有意义的,所以在选择技术方案之前,先确定业务需求。如果只是个新闻应用,就不要为了让用户在最短的时间内得到推送而维持一个长连接。相比之下,用户更在乎流量和电量。如果是个IM应用,好友发了消息之后关小时才看到,那用户也会骂娘的。
所以,实时性高、可以让用户无视流量、甘心情愿为了用产品的这个功能而宁愿多充几次电的,push是个好选择。
当然,不要忘记加个提示,再弄个开关,让用户有知情权利和选择的空间。否则,用户可能会用卸载来抗议,那就得不偿失了。