我开发的系统包括:Android Mobile上的套接字服务器和PC上的套接字客户端。为了检查与客户端的连接,我每隔1秒从服务器发送一个" "
字符。
但有时候,我得到了例外:
java.net.SocketException: sendto failed: EPIPE (Broken pipe)
at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:506)
at libcore.io.IoBridge.sendto(IoBridge.java:475)
at java.net.PlainSocketImpl.write(PlainSocketImpl.java:507)
at java.net.PlainSocketImpl.access$100(PlainSocketImpl.java:46)
at java.net.PlainSocketImpl$PlainSocketOutputStream.write(PlainSocketImpl.java:269)
at java.io.OutputStream.write(OutputStream.java:82)
at com.foxconn.cnsbgit.mobileterminal.MainActivity$ServerThread.run(MainActivity.jaa:527)
at java.lang.Thread.run(Thread.java:856)
Caused by: libcore.io.ErrnoException: sendto failed: EPIPE (Broken pipe)
at libcore.io.Posix.sendtoBytes(Native Method)
at libcore.io.Posix.sendto(Posix.java:151)
at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:177)
at libcore.io.IoBridge.sendto(IoBridge.java:473)
... 6 more
发送Thread
以检查连接如下:
while (true) {
if (client != null) {
try {
client.getOutputStream().write(" ".getBytes()); // Get exception when sending character
Thread.sleep(1000);
mHandler.post(new Runnable() {
@Override
public void run() {
txtConnectionStatus.setText(R.string.smoConnectOK);
}
});
} catch (Exception e) {
e.printStackTrace(); // Get exception at here
mHandler.post(new Runnable() {
@Override
public void run() {
if !txtConnectionStatus.getText().toString().contains("FAIL")) {
txtConnectionStatus.setText(R.string.connectionFailString);
}
}
});
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
更新 然后我输入并向客户发送数据。当心跳和数据同时发送时连接是否丢失? :
public class SendDataThread implements Runnable {
@Override
public void run() {
try {
if (client != null) {
sendDataStream = client.getOutputStream();
sendDataStream.write(dataSend); //dataSend is a byte array
sendDataStream.flush();
mHandler.post(new Runnable() {
@Override
public void run() {
edtCommand.selectAll();
}
});
}
} catch (final Exception e) {
mHandler.post(new Runnable() {
@Override
public void run() {
txtRec.setText(e.toString());
}
});
}
}
}
答案 0 :(得分:3)
当Android保持空闲状态时,设备会锁定,然后进入深度睡眠模式。在深度睡眠模式下,Android系统会关闭现有的网络连接,如TCP或UDP。如果您的应用程序连接到服务器,它将失去与服务器的连接,并尝试根据为客户端配置的重新连接尝试方法重新连接。但是,如果您的应用程序是服务器,则所有客户端都将失去与服务器的连接,您必须在服务器中再次启动套接字并尝试再次从客户端连接。
长时间保持TCP连接打开可能不是移动设备的好选择,因为TCP连接不能与睡眠的计算机良好地交互。问题的情况是:您的Android用户在您的应用运行时让他的Android设备进入休眠状态,然后远程用户的程序(或TCP连接另一端的任何内容)通过TCP流。远程用户的程序永远不会从Android设备获得任何ACK,因为Android设备当然处于睡眠状态,因此远程设备的TCP堆栈假设它发送的TCP数据包必定已丢失,并且它通过增加其超时时间,减少其TCP窗口大小(也称为TCP-packets-number-of-in-flight-at-once)和重新发送TCP数据包来响应。但Android设备仍处于睡眠状态,因此同样的事情再次发生。结果是几分钟后,TCP连接的远程端已经放慢到即使Android设备被唤醒的程度,TCP连接可能太慢而无法使用 - 此时你的程序将需要关闭陷入困境的TCP连接,并启动一个新的,所以为什么还要努力保持它开放?
<强>解决方案强>
获取PARTIAL_WAKE_LOCK,并在屏幕熄灭时陷阱。然后 禁用并重新启用wifi。这有效,因为只有过滤器 当屏幕熄灭时打开,所以用屏幕开始wifi 关闭将保持工作,直到屏幕再次关闭。
答案 1 :(得分:1)
但有时候,我得到了例外:
java.net.SocketException:sendto failed:EPIPE(Broken pipe)
如果您写入套接字但对等方已关闭套接字,则会触发EPIPE。因此,此异常表示您无法再通过此套接字进行通信。
答案 2 :(得分:0)
您的系统完全按照设计运行。你发送了心跳,它失败了,你已经检测到一个死连接。这就是代码的目的。