socketio / socket.io-client-java

Full-featured Socket.IO Client Library for Java, which is compatible with Socket.IO v1.0 and later.
https://socketio.github.io/socket.io-client-java/installation.html
Other
5.33k stars 975 forks source link

socket.emit() from the client slows down all threads for 2 milliseconds #376

Open Deery50 opened 7 years ago

Deery50 commented 7 years ago

I'm using this library with LibGDX and I have all of my socket related activity in a different thread from the LibGDX graphics thread. It runs perfectly fine for all received requests but every time I try to emit a new request from the client, every single thread I have (including the graphics thread) freezes for 2 milliseconds (I calculated). To reiterate, this is when I call "socket.emit(id, data);" from the client. For good measure I've got the code of Client.java below which contains everything I have that deals with this socket library. The issue occurs on line 133 with "socket.emit("move", data);"

EDIT: After Testing around more with this. If the client receives a request very often, the same effect of every thread slowing down occurs.

public class Client implements Runnable {

private GameState gs;
private Socket socket;
private static float UPDATE_TIME = 1/60f;
private static float timer = 0;
private String server = "http://localhost:8080/";

public Client(GameState gs) {
    this.gs = gs;

}

@Override
public void run() {
    try {
        socket = IO.socket(server);
    } catch (URISyntaxException e) {
        e.printStackTrace();
    }
    socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            Gdx.app.log("SocketIO", "Connected");
            gs.connectionState = GameState.ConnectionState.DOWNLOADING;
        }
    }).on("init", new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            gs.mapDataString = (String) args[0];
            gs.me = gs.newPlayer(true);
            gs.me.x = loadNumberType(args[1]);
            gs.me.y = loadNumberType(args[2]);
            gs.me.id = (String) args[3];

            try {
                JSONArray players = (JSONArray) args[4];
                for(int i = 0; i < players.length(); i++) {
                    JSONObject playerObject = players.getJSONObject(i);
                    String id = playerObject.getString("id");
                    float x = (float) playerObject.getDouble("x");
                    float y = (float) playerObject.getDouble("y");
                    int rotation = playerObject.getInt("rotation");
                    GameState.Player player = gs.newPlayer(false, id, x, y, 0, 0, rotation);
                    gs.getIndexedPlayers().put(id, player);
                    if(!gs.getConnectedPlayerIDS().contains(id))
                        gs.getConnectedPlayerIDS().add(id);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
            gs.connectionState = GameState.ConnectionState.READING;
        }
    }).on("newplayer", new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            String id = (String) args[2];
            if(!id.equals(gs.me.id)) {
                float x = loadNumberType(args[0]);
                float y = loadNumberType(args[1]);

                GameState.Player newPlayer = gs.newPlayer(false, (String) args[2], x, y, 0, 0, 0);
                gs.getIndexedPlayers().put(id, newPlayer);
                if (!gs.getConnectedPlayerIDS().contains(id))
                    gs.getConnectedPlayerIDS().add(id);
            }
        }
    }).on("delplayer", new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            String id = (String) args[0];
            if(gs.getConnectedPlayerIDS().contains(id))
                gs.getConnectedPlayerIDS().remove(id);
            if(gs.getIndexedPlayers().containsKey(id))
                gs.getIndexedPlayers().remove(id);
        }
    }).on("updateplayer", new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            try {
                JSONObject updateInfo = (JSONObject) args[0];
                String id = updateInfo.getString("id");
                if(!id.equals(gs.me.id)) {
                    float x = (float) updateInfo.getDouble("x");
                    float y = (float) updateInfo.getDouble("y");
                    int rotation = (int) updateInfo.getInt("rotation");
                    if (gs.getIndexedPlayers().containsKey(id)) {
                        GameState.Player p = gs.getIndexedPlayers().get(id);
                        p.x = x;
                        p.y = y;
                        p.rotation = rotation;
                    }
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }).on("getposition", new Emitter.Listener() {
        @Override
        public void call(Object... args) {
            float oldX = loadNumberType(args[0]);
            float oldY = loadNumberType(args[1]);
            int oldRotation = Integer.parseInt(args[2].toString());
            GameState.Player me = gs.me;
            if(me != null && (me.x != oldX || me.y != oldY || me.rotation != oldRotation)) {
                JSONObject data = new JSONObject();
                try {
                    data.put("id", me.id);
                    data.put("x", me.x);
                    data.put("y", me.y);
                    data.put("rotation", me.rotation);
                    data.put("xVector", me.xVector);
                    data.put("yVector", me.yVector);
                    socket.emit("move", data);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }
    });
    socket.connect();
}

private float loadNumberType(Object o) {
    return Float.parseFloat(o.toString());
}

public void dispose() {

}

} `

Xakinlee commented 6 years ago

Bro i have the same problem.. U solved it??????

alexkomazec commented 2 years ago

@Xakinlee @Deery50 , guys, did you solve the problem? I also have the same issue. By measuring socket.emit processing time (I did 3 tests) found that:

  1. If I try to make test loop for example for loop < 1000 just to do stress test Result is ===> elapsedTime: 1500 ns (about) (test foor loop is placed in public void create() )
  2. If I try to make just to spam socket.emit in every render iteration (60 times a second ) Result is ====> elapsedTime: 273300 ns (about)
  3. If I put the test loop from the previous test into public void render() Result is ===>

render elapsedTime: 245100 ns (Look at this, this is a first iteration in for loop in one render cycle, very weird) elapsedTime: 5600 ns (this is the second iteration in for loop in the same render cycle) elapsedTime: 600 ns elapsedTime: 700 ns elapsedTime: 300 ns elapsedTime: 400 ns elapsedTime: 300 ns

processing time in third, fourth, n-th iteration in the for loop look much better than first/second for some reason. This is weird situation that I found, and have no answer for this behaviour. Also it will be good if you guys have somne answers or some advices. Best regards!

johnnyrainbow commented 1 year ago

Same issue :(