java.net.SocketException : sendto failed: EPIPE (Broken pipe) When sending character to check socket connection

标签 java android multithreading sockets

我开发的系统包括:Android Mobile上的socket服务器和PC上的socket客户端。为了检查与客户端的连接,我每 1 秒从服务器发送一个 "" 字符。

但有时,我会遇到异常(exception):

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());
                }
            });
        }
    }
}

最佳答案

当 Android 保持空闲时,设备会锁定,然后进入深度 sleep 模式。在深度 sleep 模式下,Android 系统会关闭现有的网络连接,例如 TCP 或 UDP。如果您的应用程序连接到服务器,它将失去与服务器的连接,并尝试根据为客户端配置的重新连接尝试方法重新连接。但是,如果您的应用程序是服务器,则所有客户端都将失去与服务器的连接,并且您必须在服务器中再次启动套接字并尝试从客户端再次连接。

对于移动设备来说,长时间保持 TCP 连接打开可能不是一个好的选择,因为 TCP 连接不能与进入休眠状态的计算机很好地交互。问题场景如下:当您的应用程序运行时,您的 Android 用户将其 Android 设备置于 sleep 状态,然后远程用户的程序(或 TCP 连接另一端的任何程序)通过 TCP 流发送一些数据。远程用户的程序永远不会从 Android 设备返回任何 ACK,因为 Android 设备当然处于 sleep 状态,因此远程设备的 TCP 堆栈假设它发送的 TCP 数据包一定已经丢失,并且它通过增加超时时间来响应,减小其 TCP 窗口大小(也称为一次允许传输的 TCP 数据包数量),并重新发送 TCP 数据包。但Android设备仍然处于 sleep 状态,因此同样的事情再次发生。结果是,几分钟后,TCP 连接的远程端已经减慢到这样的程度,即使 Android 设备被唤醒,TCP 连接也可能太慢而无法使用——此时您的无论如何,程序都需要关闭陷入困境的 TCP 连接并启动一个新的连接,那么为什么还要费心让它保持打开状态呢?

解决方案

Acquire a PARTIAL_WAKE_LOCK, and trap when the screen goes off. Then disable and reenable the wifi. This works because the filter only turns on when the screen goes off, so starting wifi with the screen off will keep it working until the screen goes off again.

关于java.net.SocketException : sendto failed: EPIPE (Broken pipe) When sending character to check socket connection,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33361031/

相关文章:

java - objective-c 和 Java,或者 iPhone 和 Android 之间有什么巨大的区别吗?

java - 在 Firestore 中找不到文档数据,返回 null

c++ - clang 3.0 + libc++ 中的 std::async 不起作用?

java - java中的LinkedBlockingQueue和写锁

c# - Silverlight 和非 UI 线程中的回调

java - 使用 queueEvent() 在渲染器和另一个类之间传递变量

java - java中的静态初始化

java - 乘以概率矩阵,大量迭代时的值不正确

安卓市场发布: 'android:icon' attribute: attribute is not a string value

java - 您究竟将数组放在代码中的什么位置?