我用Java为Android客户端和PC服务器创建了一个分布式应用程序(在我的例子中是Windows)。 Android应该永久保持连接,以便能够接收推送通知。所以有一个后台服务可以在关闭屏幕后继续存在。 (请不要告诉我使用GCM。它超出了范围,因为我必须连接Internet。)为了进行测试,客户端每5分钟发送一个自制的(应用程序层)ping packet
到服务器,服务器(在延迟之后)发送回pong
作为回报被确认(ack
)。当服务器收到确认时,延迟增加25秒。
然而,随机 - 似乎 - 服务器声称客户端已经非正常地关闭了此错误消息的连接:
android java.io.IOException: An existing connection was forcibly closed by the remote host
我注意到有一些因素会延迟(不解决!)这个问题:
以下组件我确定没有影响:
如果我在Linux(Ubuntu)机器上运行服务器程序,则没有连接失败。
这些连接问题可能是什么原因?如何在不切换到Linux的情况下摆脱它们?
答案 0 :(得分:0)
我在OS Version 4.3上遇到了同样的问题。我假设你正在服务这个片段可能会帮助你保持你的连接活着
private PowerManager.WakeLock mWakeLock;
public override void OnCreate ()
{
PowerManager pm = (PowerManager) GetSystemService(Context.PowerService);
mWakeLock = pm.NewWakeLock (WakeLockFlags.Partial, "PartialWakeLockTag");
mWakeLock.Acquire();
}
public override void OnDestroy ()
{
mWakeLock.Release();
}
显然,通过保持设备CPU处于活动状态,您将快速饮用电池汁
答案 1 :(得分:0)
经过大量研究后,我自己想出了解决方案......
此处的一个主要问题是Android设备在未被主动使用时输入的deep sleep
。我不想使用唤醒锁来减少电池电量。我没有找到Android深度睡眠模式的正确描述,但是SystemClock documentation中提到了它。
然而,深度睡眠通常不是wifi通信的问题。 Android以某种方式设法在深度睡眠中接收网络数据包,但不一定唤醒接收应用程序。相反,它们会在应用程序变为活动状态时传送到应用程序(例如,由于用户交互或警报事件)。
使用Windows时出现问题,因为自Windows Vista和2008以来,ARP缓存条目的超时时间已降至15-45秒(1.)。这意味着Windows每隔30秒就会询问Android设备的MAC地址。这可以使用网络嗅探器确认。 (“谁拥有192.168.0.3?告诉192.168.0.2”)
如果Android正在睡觉,它将无法响应。经过30到300秒之间的一些超时(我无法确定它更精确),显然Windows声明所有打开的TPC连接都已损坏。 (那就是上面的IOException来自。)
因此解决方案是静态设置Android设备的ARP条目(2.)或大规模增加ARP缓存超时(3.)。
让我们先尝试第二种方法:
以管理员身份打开cmd
并获取网络接口ID:
netsh interface ipv4 show interfaces
使用id(此处为11)增加超时基数值(默认值:30000):
netsh interface ipv4 set interface 11 basereachable=3000000
我还增加了重传间隔(默认值:1000)
netsh interface ipv4 set interface 11 retransmittime=10000
输入netsh interface ipv4 show interface 11
确认
Interface Local Area Connection Parameters
----------------------------------------------
IfLuid : ethernet_6
IfIndex : 11
State : connected
Metric : 20
Link MTU : 1500 bytes
Reachable Time : 2850000 ms
Base Reachable Time : 3000000 ms
Retransmission Interval : 10000 ms
...
http://support.microsoft.com/kb/949589
修改强>
虽然增加这些超时值会大大增强情况,但仍会出现同样的问题。所以这变得更加技术化了:
似乎Linux下的ARP超时在/proc/sys/net/ipv4/neigh/eth0/gc_stale_time
中指定,默认为60秒。因此,此值与Windows默认值相当。
然而,主要区别在于ARP实施:
当Windows需要发送IP包并且该条目的ARP缓存超时时,广播请求“谁有IP?告诉我”。当Linux想要这样做时,它使用最后一个已知的MAC地址并将其用作请求“谁拥有IP?告诉我”的接收者。 (这称为单播民意调查,在RFC 1122中定义,第2.3.2.1节(2) - >(1.))
显然,Android认为单播请求比广播更重要(解决FFFFFF:FFFFFF)并立即回答(因此它从深度睡眠中升起来这样做)。结果:Linux立即获得ARP答案,而Windows则不会因此杀死所有TCP连接。
http://tools.ietf.org/html/rfc1122#page-23
<强> EDIT2 强>
我找到了另一个解决方案:
让客户端定期广播自己的MAC(比服务器上的ARP缓存超时更频繁)。这可以使用arpping -c 1 -A -I wlan0 192.168.0.4
完成。这里最大的问题:Android上没有arpping,Java不支持发送ARP数据包。由于我不想要本地实现,我尝试从上面开始的第二种方法。
在Windows服务器上设置静态路由:
找出网络接口名称:netsh interface show interface
,例如“本地连接”。然后添加静态ARP路由:netsh interface ip add neighbors "Local Area Connection" "192.168.0.4" "a0-0b-ba-44-f9-3d"
<强> CONFIRMED 强>
只是想确认使用如上所述的静态ARP路由来解决问题。没有连接失败。在我的测试中,我至少每5分钟向服务器或Android客户端发送一条消息。没有数据包丢失。测试时间:10.5小时。