【问题标题】:java.net.SocketException: sendto failed: EPIPE (Broken pipe) When sending character to check socket connectionjava.net.SocketException: sendto failed: EPIPE (Broken pipe) 发送字符以检查套接字连接时
【发布时间】:2015-10-27 06:13:55
【问题描述】:

我开发的系统包括:Android Mobile上的socket server和PC上的socket client。为了检查与客户端的连接,我每 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());
                }
            });
        }
    }
}

【问题讨论】:

    标签: java android multithreading sockets


    【解决方案1】:

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

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

    解决方案

    获取 PARTIAL_WAKE_LOCK,并在屏幕关闭时捕获。然后 禁用和重新启用wifi。这是有效的,因为只有过滤器 屏幕熄灭时打开,因此使用屏幕启动wifi off 将继续工作,直到屏幕再次熄灭。

    【讨论】:

      【解决方案2】:

      但有时,我得到了例外:

      java.net.SocketException: sendto 失败: EPIPE (Broken pipe)

      如果您写入套接字但对等方已经关闭了套接字,则会触发 EPIPE。因此,此异常表明您无法再通过此套接字进行通信。

      【讨论】:

      • 经常写" " 可能是导致连接关闭的原因,兄弟?
      • @MrNeo:“”不会关闭连接,服务器会。由于我不知道您的服务器是做什么的,我无法确定过多的“”是否会导致它关闭连接。
      • 我已更新我的问题以获取更多信息。当我同时发送心跳和数据时,我的连接是否丢失了?
      • @MrNeo:再说一遍:服务器关闭了连接。为什么这样做取决于服务器。添加更多客户端代码进行分析是没有意义的。查看服务器,看看它关闭连接的原因。
      • 是的,我会再检查一遍。
      【解决方案3】:

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

      【讨论】:

      • 我已更新我的问题以获取更多信息。当我同时发送心跳和数据时,我的连接是否丢失了?
      • @MrNeo No. 当对端关闭他的端或检测到网络故障时丢失。对等端的行为是否正常?
      • 我发现如果我打开什么都不做,时间长了就ok了。但是如果我开始发送和获取数据大约第十次,就会发生异常:(
      • 如果你不回答我提出的问题,我帮不了你。
      • 啊,对不起,兄弟。对等体表现正常,因为它是一个系统并且可以长时间使用而没有问题。问题来自我在 Android 手机上的服务器。
      猜你喜欢
      • 2013-01-15
      • 2014-06-14
      • 1970-01-01
      • 2013-02-07
      • 1970-01-01
      • 1970-01-01
      • 2018-10-29
      • 1970-01-01
      相关资源
      最近更新 更多