简体   繁体   English

java.net.SocketException:sendto失败:EPIPE(断开的管道)发送字符以检查套接字连接时

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

I develop a system include: socket server on Android Mobile and socket client on PC. 我开发的系统包括:Android Mobile上的套接字服务器和PC上的套接字客户端。 And to check the connection with client, I had sent a " " character every 1 second from server. 为了检查与客户端的连接,我每隔1秒从服务器发送一个" "字符。

But sometimes, I got the 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

The sending Thread to check connection is following: 发送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();
              }
          }
     }
}

Updated: Then I had input and sent data to client. 更新:然后我输入并发送数据到客户端。 Is connection lost when both heartbeat and data send at the same time? 当心跳和数据同时发送时,连接会丢失吗? :

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

When an Android is kept idle, the device locks and then it goes to deep sleep mode. 当Android保持空闲状态时,设备会锁定,然后进入深度睡眠模式。 In deep sleep mode the Android system, closes the existing network connections like TCP or UDP. 在深度睡眠模式下,Android系统关闭现有的网络连接,例如TCP或UDP。 If your app is connected to a server, it loses connection to the server and tries to reconnect based on the reconnect attempt methods configured for the client. 如果您的应用程序已连接到服务器,则它将失去与服务器的连接,并尝试根据为客户端配置的重新连接尝试方法来重新连接。 But if your app is the server, all the client will lose connection to the server, and you have to start the socket again in server and try to connect once again from the clients. 但是,如果您的应用是服务器,则所有客户端都将失去与服务器的连接,您必须在服务器中再次启动套接字,然后尝试再次从客户端连接。

Keeping a TCP connection open for extended periods may not be a good option for a mobile device, because TCP connections don't interact well with computers that go to sleep. 对于移动设备来说,长时间保持TCP连接的打开不是一个好的选择,因为TCP连接与睡眠的计算机无法很好地交互。 The problem scenario would be this: your Android user puts his Android device to sleep while your app is running, and then the remote user's program (or whatever is at the other end of the TCP connection) sends some data over the TCP stream. 问题场景是这样的:您的Android用户在应用程序运行时将其Android设备置于睡眠状态,然后远程用户的程序(或TCP连接另一端的任何内容)通过TCP流发送一些数据。 The remote user's program never gets any ACKs back from the Android device, because of course the Android device is asleep, so the remote device's TCP stack assumes that the TCP packets it sent must have been lost, and it responds by increasing its timeout period, decreasing its TCP window size (aka number-of-TCP-packets-allowed-in-flight-at-once), and resending the TCP packets. 远程用户的程序永远不会从Android设备获取任何ACK,因为Android设备当然处于睡眠状态,因此远程设备的TCP堆栈假定它发送的TCP数据包一定已经丢失,并且它会通过增加超时时间来做出响应,减小其TCP窗口大小(又称一次允许飞行中的TCP数据包数),然后重新发送TCP数据包。 But the Android device is still asleep, and thus the same thing happens again. 但是Android设备仍处于睡眠状态,因此同样的事情再次发生。 The upshot is that a few minutes later, the remote end of the TCP connection has slowed down to the point where even if the Android device was to wake up, the TCP connection will likely be too slow to be usable -- at which point your program will need to close the bogged-down TCP connection and start up a fresh one anyway, so why bother trying to keep it open? 结果是,几分钟后,TCP连接的远程端速度变慢,以至于即使要唤醒Android设备,TCP连接也可能太慢而无法使用-此时,您的程序将需要关闭陷入困境的TCP连接并无论如何都要启动一个新连接,那么为什么还要尝试使其保持打开状态呢?

Solution

Acquire a PARTIAL_WAKE_LOCK, and trap when the screen goes off. 获取PARTIAL_WAKE_LOCK,并在屏幕关闭时捕获。 Then disable and reenable the wifi. 然后禁用并重新启用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. 之所以可行,是因为过滤器仅在屏幕关闭时才打开,因此在屏幕关闭时启动wifi将使其保持工作状态,直到屏幕再次关闭为止。

But sometimes, I got the exception: 但有时,我得到了例外:

java.net.SocketException: sendto failed: EPIPE (Broken pipe) java.net.SocketException:sendto失败:EPIPE(断开的管道)

EPIPE is triggered if you write to a socket but the peer has closed the socket already. 如果您写入套接字但对等方已经关闭了套接字,则会触发EPIPE。 Thus this exception indicates that you can no longer communicate through this socket. 因此,此异常表明您无法再通过此套接字进行通信。

Your system is working exactly as designed. 您的系统完全按照设计运行。 You sent the heartbeat, it fails, you've detected a dead connection. 您发送了心跳,但失败,检测到连接中断。 That's the purpose of the code. 这就是代码的目的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 java.net.SocketException:sendto失败:Android上的EPIPE(管道断开) - java.net.SocketException: sendto failed: EPIPE (Broken pipe) on Android Android:套接字-java.net.SocketException:sendto失败:EPIPE(管道断开) - Android : Socket - java.net.SocketException: sendto failed: EPIPE (Broken pipe) 使用NanoHttpd进行视频流传输,错误:java.net.SocketException:sendto failed:EPIPE(Broken pipe) - Video streaming using NanoHttpd, Error: java.net.SocketException: sendto failed: EPIPE (Broken pipe) java.net.SocketException有什么区别:Connection reset和java.net.SocketException:Broken Pipe? - What is the difference between java.net.SocketException: Connection reset and java.net.SocketException: Broken Pipe? 相互SSL异常发送警报:java.net.SocketException:管道断开(写入失败) - Mutual SSL Exception sending alert: java.net.SocketException: Broken pipe (Write failed) java.net.SocketException:SMTP管道损坏 - java.net.SocketException: Broken pipe with SMTP java.net.SocketException:管道损坏 - java.net.SocketException: Broken pipe java.net.SocketException:管道损坏 - java.net.SocketException: Broken pipe Android java.net.SocketException:套接字失败 - Android java.net.SocketException: socket failed Java rabbitmq SSL 问题 java.net.SocketException: Broken pipe (Write failed) - Java rabbitmq SSL issue java.net.SocketException: Broken pipe (Write failed)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM