java.net.SocketException:sendto failed:EPIPE(Broken pipe)发送字符时检查套接字连接

时间:2015-10-27 06:13:55

标签: java android multithreading sockets

我开发的系统包括: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());
                }
            });
        }
    }
}

3 个答案:

答案 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)

您的系统完全按照设计运行。你发送了心跳,它失败了,你已经检测到一个死连接。这就是代码的目的。