Socket.io-client-java: disconnecting unexpectedly

Created on 17 Mar 2015  Â·  31Comments  Â·  Source: socketio/socket.io-client-java

After a period the application disconnecting from the server, and i can't produce a pattern for this disconnection. i am implementing chat application due to this disconnection i find the users disconnected unexpectedly. so what i should i do to solve this case ?

Another issue. when i send message i can't know if it arrived to the other side or not ? is there a callback functions in the emit request guide me if it failed to reach or not ?

duplicate

Most helpful comment

FIXED THE BUG!
The nature of Socket IO is that the sockets timeout (or in this case, DISCONNECTS) if there are no activities present in the socket. When your phone goes to idle mode (when it sleeps), there is no constant connection that checks whether the app is active or not. One simple way to keep the socket alive is to send constant heartbeats (or ping pongs) every 20-30 seconds or so!

Server-side:

io.sockets.on('connection', function (socket) {
    socket.on('pong', function(data){
        console.log("Pong received from client");
    });
    setTimeout(sendHeartbeat, 25000);

    function sendHeartbeat(){
        setTimeout(sendHeartbeat, 25000);
        io.sockets.emit('ping', { beat : 1 });
    }
});

Client-Side:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mSocket.connect();
    mSocket.on("ping", sendPong);
}

private Emitter.Listener sendPong = new Emitter.Listener() {
        @Override
        public void call(final Object... args) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    JSONObject data = (JSONObject) args[0];
                    String ping;
                    try {
                        ping = data.getString("ping");
                    } catch (JSONException e) {
                        return;
                    }
                    if(ping.equals("1")){
                        SocketSingleton.get(getApplicationContext()).getSocket().emit("pong", "pong");
                    }
                    Log.e("SOCKETPING", "RECEIVED PING! ");
                }
            });
        }
    };

This WILL work! And this does NOT drain battery! This is the BEST fix I have found so far!

All 31 comments

looks the same issue with https://github.com/nkzawa/socket.io-client.java/issues/84, and I couldn't reproduce this at all. Let me know if you know how to reproduce.

capture

This event happens at 1.20 minutes after locking the screen. But if the application is in background this don't happen.
I'm using the latest version of socket,io on my server and the latest version of this library on Android

@nkzawa Hello, first of all thanks for this awesome client! but I too have this same exact problem. I have been trying to understand this problem and I have got some data.

This problem happens when my phone is not connected to the computer. If my phone is plugged into the computer, Android Studio constantly keeps the phone active, which in turn keeps the sockets on. However, if you have your phone disconnected from your computer, the phone sleeps after 2-5 minutes of inactivity, the socket disconnects by itself. Once I resume my phone, the socket reconnects after a good 5 minutes.

Please do fix this problem. It will be a great help if you do!

The way I setup my app is like this: I have created a singleton class for the sockets so I can use one instance of the connection in every fragment.

public class SocketSingleton {
    private static SocketSingleton instance;
    private static final String SERVER_ADDRESS = "http://192.168.1.15:8080/";
    private Socket mSocket;
    private Context context;

    public SocketSingleton(Context context) {
        this.context = context;
        this.mSocket = getServerSocket();
    }

    public static SocketSingleton get(Context context){
        if(instance == null){
            instance = getSync(context);
        }
        instance.context = context;
        return instance;
    }

    private static synchronized SocketSingleton getSync(Context context) {
        if(instance == null){
            instance = new SocketSingleton(context);
        }
        return instance;
    }

    public Socket getSocket(){
        return this.mSocket;
    }

    public Socket getServerSocket() {
        try {
            IO.Options opts = new IO.Options();
            opts.forceNew = true;
            opts.reconnection = true;
            mSocket = IO.socket(SERVER_ADDRESS, opts);
            return mSocket;
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }
}

However, the socket is connected only in the MainActivity. The fragments are used to turn on and off message events.

So in summary, to reproduce this problem:
1) Make sure your phone is plugged off of the computer.
2) Open your app and make sure your socket connects
3) Now, let your phone go to sleep (Do NOT close the app).
4) Give it a few minutes and it will disconnect automatically.

So please try and fix this problem. Again, thanks so much for this great client!

FIXED THE BUG!
The nature of Socket IO is that the sockets timeout (or in this case, DISCONNECTS) if there are no activities present in the socket. When your phone goes to idle mode (when it sleeps), there is no constant connection that checks whether the app is active or not. One simple way to keep the socket alive is to send constant heartbeats (or ping pongs) every 20-30 seconds or so!

Server-side:

io.sockets.on('connection', function (socket) {
    socket.on('pong', function(data){
        console.log("Pong received from client");
    });
    setTimeout(sendHeartbeat, 25000);

    function sendHeartbeat(){
        setTimeout(sendHeartbeat, 25000);
        io.sockets.emit('ping', { beat : 1 });
    }
});

Client-Side:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mSocket.connect();
    mSocket.on("ping", sendPong);
}

private Emitter.Listener sendPong = new Emitter.Listener() {
        @Override
        public void call(final Object... args) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    JSONObject data = (JSONObject) args[0];
                    String ping;
                    try {
                        ping = data.getString("ping");
                    } catch (JSONException e) {
                        return;
                    }
                    if(ping.equals("1")){
                        SocketSingleton.get(getApplicationContext()).getSocket().emit("pong", "pong");
                    }
                    Log.e("SOCKETPING", "RECEIVED PING! ");
                }
            });
        }
    };

This WILL work! And this does NOT drain battery! This is the BEST fix I have found so far!

Any follow-up on this? If I understand right, the solution above requires server to actively ping the client. Not sure if it's good for server scaling.

Umm the library internally sends and receives ping/pong messages, so basically you don't need to do that. And I'd like to know whether this still happens on the latest version.

I solved this problem in the same way hours ago, but I don't think that this is an elegant resolution for that.

@EpsilonOrionis could you please paste some logs here?

Logs about what?

@Yoosuf29 Could you please paste how to use the Singleton class in MainActivity.java? I can't connect to my server, but I would use this method, it seems to be better than opening and closing connections through all fragments.

@EpsilonOrionis
In my experience, I do not think u need to establish a Singleton method if you have only ONE activity. You can open the connection in your main class, and turn on and off sockets in your fragment. And of course, turn off the sockets on onDestroy method in your fragment classes. I just used Singleton as a security to make sure I don't create multiple instances if Android somehow screws up.

So, here is my Singleton class:

public class SocketSingleton {
    private static SocketSingleton instance;
    private static final String SERVER_ADDRESS = "http://YOUR_ADDRESS:PORT/";
    private Socket mSocket;
    private Context context;

    public SocketSingleton(Context context) {
        this.context = context;
        this.mSocket = getServerSocket();
    }

    public static SocketSingleton get(Context context){
        if(instance == null){
            instance = getSync(context);
        }
        instance.context = context;
        return instance;
    }

    private static synchronized SocketSingleton getSync(Context context) {
        if(instance == null){
            instance = new SocketSingleton(context);
        }
        return instance;
    }

    public Socket getSocket(){
        return this.mSocket;
    }

    public Socket getServerSocket() {
        try {
            IO.Options opts = new IO.Options();
            opts.forceNew = true;
            opts.reconnection = true;
            mSocket = IO.socket(SERVER_ADDRESS, opts);
            return mSocket;
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }
}

And my MainActivity:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        SocketSingleton.get(this).getSocket().connect();
        SocketSingleton.get(getApplicationContext()).getSocket().emit("joinSocket", SEND_USER_ID);

        /// Send pongs to keep connection active;
        SocketSingleton.get(this).getSocket().on("ping", sendPong);

        SocketSingleton.get(this).getSocket().on(Socket.EVENT_RECONNECT, new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                SocketSingleton.get(getApplicationContext()).getSocket().emit("joinSocket", SEND_USER_ID);
            }
        });
    }

    private Emitter.Listener sendPong = new Emitter.Listener() {

        @Override
        public void call(final Object... args) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    JSONObject data = (JSONObject) args[0];
                    String ping;
                    try {
                        ping = data.getString("ping");
                    } catch (JSONException e) {
                        return;
                    }
                    if(ping.equals("1")){
                        SocketSingleton.get(getApplicationContext()).getSocket().emit("pong", current_user);
                    }
                    ping_counter++;
                    Log.e("SOCKETPING", "RECEIVED PING: " + ping_counter);
                    TextView pingReceived = (TextView) findViewById(R.id.pingReceived);
                    try{
                        pingReceived.setText(ping_counter + "");
                    } catch (Exception e) {

                    }
                }
            });
        }
    };

Hope this helped you! also, if you make this code better, please do consider sharing. Thanks.

I still have the exact problem in 0.5.2. I have a service running in the background that connects to socket.io onCreate and disconnects onDestroy. Has anyone here solved the problem in an elegant way instead of ponging the server every 20-30 seconds?

http://stackoverflow.com/questions/10725711/how-to-do-not-let-thread-stop-themeselves-when-in-standby-mode

This is the reason of the issue? Have someone tried PARTIAL_WAKE_LOCK?

I posted a solution using PARTIAL_WAKE_LOCK under #84 which I thought was this same issue. https://github.com/nkzawa/socket.io-client.java/issues/84 https://github.com/nkzawa/socket.io-client.java/issues/84

On Jul 23, 2015, at 2:16 PM, Naoyuki Kanezawa [email protected] wrote:

http://stackoverflow.com/questions/10725711/how-to-do-not-let-thread-stop-themeselves-when-in-standby-mode http://stackoverflow.com/questions/10725711/how-to-do-not-let-thread-stop-themeselves-when-in-standby-mode
This is the reason of the issue? Have someone tried PARTIAL_WAKE_LOCK?

—
Reply to this email directly or view it on GitHub https://github.com/nkzawa/socket.io-client.java/issues/123#issuecomment-124192435.

@bwilks128 Thanks for your post! I think that is a right solution for the issue.

UPDATE: The wake lock has reduced the frequency of this incident but not eliminated it completely. After turning on debug messages on the server side, I can see a ping timeout still occurring at random intervals. It is less frequent now but still an issue; the wake lock improved the situation but did not solve this for me. I see this issue with both my Tab 4 and my S3 so it does not seem to be specific to one device or version of Android.

UPDATE2: With the wake lock in place, I no longer have the Android device going to sleep and being unreachable. I still see some type of intermittent issue that for some reason results in a disconnect but am able to code for this now given the device is awake. This issue may have nothing to do with this library as it could be any type of network communication failure.

On Jul 23, 2015, at 3:28 PM, Naoyuki Kanezawa [email protected] wrote:

@bwilks128 https://github.com/bwilks128 Thanks for you post! I think that is a right solution for the issue.

—
Reply to this email directly or view it on GitHub https://github.com/nkzawa/socket.io-client.java/issues/123#issuecomment-124218092.

I have the same problem. How about implementing service as explained here? https://github.com/salmar/android-websockets-mobos2013/wiki/Part-3:-Building-the-Android-client-with-socket.io will that be helpful?

@Yoosuf29 Thank you! Your suggestion worked for us

@nkzawa PARTIAL_WAKE_LOCK is the worst solution. It prevents the phone from going into deep sleep to save battery which is important. Does @RedWrightShafi solution with sending ping pongs every 30 seconds from the client to server work using a backround service?

Right now Im using the ping pong workarround. But after one hour, it wont work again. Im testing with android 5.0 Any new ideas to solve this issue?

It seems that Socket.io server and client are using the options pingInterval and pingTimeout to make the heartbeat. The default values are 25 seconds and 60 seconds. Upgrading both to the latest version seems to fix reconnection issues when android sleep.

https://github.com/socketio/engine.io/blob/master/README.md#methods-1

@sandro-csimas This has been confirmed Sandro?

@alejofilaKoombea

I'm having another issue now. The client is connecting more then once after the upgrade.
Server:

circles.on('connection', function(socket) {
  var userId = socket.request._query.user;
  logger.debug('Connecting user %d', userId);
  userService.getUser(userId, ['members']).then(function(user) {
    if(user) {
      var members = user.related('members');
      members.forEach(function(member) {
        var room = getCircleRoom(member.get('circle_id'));
        socket.join(room);
      });

      socket.emit('connected');
      logger.debug('User %d connected (Socket %s)', user.id, socket.id);
      addSocket(user, socket);

      socket.on('disconnect', function() {
        logger.debug('User %d disconnected (Socket %s)', user.id, socket.id);
        removeSocket(user, socket);
      });
    } else {
      logger.error('User %d does not exist', userId);
      socket.disconnect();
    }
  }).catch(function(err) {
    logger.error('Error finding user %d', userId, err);
    socket.disconnect();
  });
});

Server log:

2016-01-15T18:10:45.448Z - ESC[34mdebugESC[39m: User 1 connected (Socket /circles#h5OXbKNB2odID4NPAAAA)
2016-01-15T18:10:45.449Z - ESC[34mdebugESC[39m: Sockets of user 1: /circles#h5OXbKNB2odID4NPAAAA

2016-01-15T18:10:53.078Z - ESC[34mdebugESC[39m: User 1 disconnected (Socket /circles#h5OXbKNB2odID4NPAAAA)
2016-01-15T18:10:53.078Z - ESC[34mdebugESC[39m: Sockets of user 1: 

2016-01-15T18:11:11.707Z - ESC[34mdebugESC[39m: User 1 connected (Socket /circles#N26DdFoLABUh9PNkAAAE)
2016-01-15T18:11:11.708Z - ESC[34mdebugESC[39m: Sockets of user 1: /circles#N26DdFoLABUh9PNkAAAE

2016-01-15T18:13:30.476Z - ESC[34mdebugESC[39m: User 1 connected (Socket /circles#zE027HKtvwZINFNRAAAF)
2016-01-15T18:13:30.479Z - ESC[34mdebugESC[39m: Sockets of user 1: /circles#N26DdFoLABUh9PNkAAAE,/circles#zE027HKtvwZINFNRAAAF

I can't confirm now because of this another issue, but yesterday for a long time the client was not disconnected.

Any news?

Anyone solved this problem?

@vijayaa, after a long time trying to solve this problem, I could not solve.
I had to migrate my solution to use FCM. Now is everything working fine.
You can use the messaging service for free.

Any news?

I am trying to fix the connection problem in hibernate mode, I used a "ping / pong" method, stayed longer connected, but still after a while disconnects unexpectedly.

Update for anyone trying to still fix this issue. I ended up not using socket.io for my next project. I realized that a constant connection is not necessary for most applications, even for apps you may think have a constant connection like messaging. The only time I see socket.io being considered for a project would be in applications when large amounts of real time data is needed, such as games. Where you want to send the client a lot of game data several times a second.

The reason why socket.io is killed when operating within a service activity is because Android may kill services when entering into deep sleep mode. The only way to properly survive during sleep mode is by either 1) Forcing the phone to never enter deep sleep (bad idea) this will drain a lot of battery, or 2) periodically wake the phone using Alarm Manager and WAKE_LOCK. You can do this manually or use a library that handles this for you. Google the keywords "Job Scheduler". I currently use https://github.com/evernote/android-job. If you wanted to keep using socket.io for your application and need to query for new data in the background when the app is closed you could quickly connect using socket.io inside your job using one of the popular job libraries out there, or use Alarm Manager manually, then after querying close the connection. However, I think the more efficient way is to use an HTTP API library to make calls to your server instead of socket.io, using something like Retrofit, volley, or okHTTP. I currently use Volley which is developed by google. You can set your job to to run periodically, or manually using Alarm Mananger and WAKE_LOCK to periodically turn on the device.

I hope this helps.

Use 0.8.3 version of io.socket remove new version 1.0.0

compile('io.socket:socket.io-client:0.8.3') {
    exclude group: 'org.json', module: 'json'
}

I had an unexpected disconnect issue, too, and the socket wouldn't reconnect. I downgraded from v1.0.0 to v0.9.0 and those issues were gone. Do not use the latest version, it's buggy!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

arora-arpit picture arora-arpit  Â·  3Comments

b95505017 picture b95505017  Â·  12Comments

arpitjoshi08 picture arpitjoshi08  Â·  3Comments

jaumard picture jaumard  Â·  4Comments

hova4 picture hova4  Â·  12Comments