0

I develop a system include: socket server on Android Mobile and socket client on PC. And to check the connection with client, I had sent a " " character every 1 second from server.

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:

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());
                }
            });
        }
    }
}
Neo
  • 1,469
  • 3
  • 23
  • 40

3 Answers3

4

When an Android is kept idle, the device locks and then it goes to deep sleep mode. In deep sleep mode the Android system, closes the existing network connections like TCP or 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. 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. 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. But the Android device is still asleep, and thus the same thing happens again. 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?

Solution

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.

Valamburi M
  • 692
  • 4
  • 17
1

But sometimes, I got the exception:

java.net.SocketException: sendto failed: EPIPE (Broken pipe)

EPIPE is triggered if you write to a socket but the peer has closed the socket already. Thus this exception indicates that you can no longer communicate through this socket.

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • writing `" "` frequently could be the reason make connection closed, bro? – Neo Oct 27 '15 at 07:32
  • @MrNeo: the " " does not close the connection, the server does. Since I have no idea what your server does I cannot determine if too much of " " will cause it to close the connection. – Steffen Ullrich Oct 27 '15 at 08:16
  • I had updated my question for more information. Did my connection lost when I sent both heartbeat and data at the same time? – Neo Oct 27 '15 at 09:12
  • @MrNeo: To say it again: the server closed the connection. Why this was done depends on the server. It makes no sense to add more client code for analysis. Look at the server and see why it closed the connection. – Steffen Ullrich Oct 27 '15 at 09:42
  • Yes, I will check it again. – Neo Oct 27 '15 at 09:55
0

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.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • I had updated my question for more information. Did my connection lost when I sent both heartbeat and data at the same time? – Neo Oct 27 '15 at 09:12
  • @MrNeo No. It is lost when the peer closes his end or a network failure is detected. Is the peer behaving normally? – user207421 Oct 27 '15 at 09:12
  • I found that if I open and do nothing, it's ok for a long time. But if I start send and get data about tenth times, exception will occur :( – Neo Oct 27 '15 at 09:17
  • I can't help you if you don't answer the questions I ask. – user207421 Oct 27 '15 at 09:18
  • ah, sorry, bro. The peer behave normally because it's a system and use for a long time without problem. The problem is from my server on Android phone. – Neo Oct 27 '15 at 09:20
  • The peer appears to have closed the connection. Is that 'normal'? – user207421 Oct 27 '15 at 09:21
  • I will check this again. You mean that when I send data as heart beat, the peer would close the connection, bro? – Neo Oct 27 '15 at 09:37
  • No, I mean it has *already* closed the connection, which is why you got the error when you sent the hearbeat. Otherwise you would have got the error later on, *nu?* And don't call me 'bro'. – user207421 Oct 27 '15 at 09:45
  • I am so sorry about that. I will check the problem again! – Neo Oct 27 '15 at 09:55