Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Continuous Connection request to server from engine.io-client #20

Closed
jeevaengg21 opened this issue Dec 19, 2019 · 14 comments
Closed

Continuous Connection request to server from engine.io-client #20

jeevaengg21 opened this issue Dec 19, 2019 · 14 comments

Comments

@jeevaengg21
Copy link

jeevaengg21 commented Dec 19, 2019

Server: Wildfly 10.1
Browser: Chrome
Frontend: Reactjs
Socket server: engine.io-server-java V 1.3.4
Socket client: engine.io-client V 3.4.0

Note: Followed the below documentation link to host the generic java engine.io server.
https://socketio.github.io/engine.io-server-java/using.html

Issue: When the UI is launched, engine.io triggers the connection request to the sever. When checking the sever log connection request is reached the servlet, now the issue is client is continuously sending the connection request to servlet and WebSocket connection is not establishing it goes like a never-ending process. Attacthed the source for the reference please check and advice want went wrong in the code.

image

Project Structure:

image

ReactJS as front-end:

App.JS

import React from 'react';
var enginesocket = require('engine.io-client')('ws://localhost:8080', { transport: ["websocket"], 
 upgrade: true, reconnection: false });

class App extends React.Component {

 componentDidMount() {
    
    enginesocket.on('open', function () {
      console.log("Opened");
      enginesocket.on('message', function (data) {
        console.log("Message from server :: ", data);
      });
    });
  }
}

EngineIoServlet -

URLPattens is kept as "/" since WAR file name is "engine.io". So the context "/engine.io/" will be exposed by wildfly server.

@WebServlet(name = "EngineIoServlet", urlPatterns = {"/"})
public class EngineIoServlet extends HttpServlet {

    private final EngineIoServer mEngineIoServer = new EngineIoServer();
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("mEngineIoServer?? " + mEngineIoServer);        
        mEngineIoServer.handleRequest(request, response);
        mEngineIoServer.on("connection", new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                EngineIoSocket socket = (EngineIoSocket) args[0];
                // Do something with socket like store it somewhere
                System.out.println("socket :: " + socket);
                socket.on("packet", new Emitter.Listener() {
                    @Override
                    public void call(Object... args) {
                        Packet packet = (Packet) args[0];
                        // Do something with packet.
                        System.out.println("packet :: " + packet.data);
                    }
                });            
                socket.on("message", new Emitter.Listener() {
                    @Override
                    public void call(Object... args) {
                        Object message = args[0];
                        // message can be either String or byte[]
                        // Do something with message.
                        System.out.println("message ::" + message);
                    }
                });
                socket.send(new Packet<>(Packet.MESSAGE, "foo"));
            }
        });

    }

ApplicationServerConfig


public final class ApplicationServerConfig implements ServerApplicationConfig {

    @Override
    public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> endpointClasses) {
        final HashSet<ServerEndpointConfig> result = new HashSet<>();
        result.add(ServerEndpointConfig.Builder
                .create(EngineIoEndpoint.class, "/")
                .build());

        return result;
    }

    @Override
    public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) {
        return null;
    }
}

EngineIoEndpoint

public final class EngineIoEndpoint extends Endpoint {

    private Session mSession;
    private Map<String, String> mQuery;
    private EngineIoWebSocket mEngineIoWebSocket;

    private EngineIoServer mEngineIoServer; // The engine.io server instance

    @Override
    public void onOpen(Session session, EndpointConfig endpointConfig) {
        mSession = session;
        mQuery = ParseQS.decode(session.getQueryString());

        System.out.println("inside socket onOpen");

        mEngineIoWebSocket = new EngineIoWebSocketImpl();

        /*
         * These cannot be converted to lambda because of runtime type inference
         * by server.
         */
        mSession.addMessageHandler(new MessageHandler.Whole<String>() {
            @Override
            public void onMessage(String message) {
                mEngineIoWebSocket.emit("message", message);
            }
        });
        mSession.addMessageHandler(new MessageHandler.Whole<byte[]>() {
            @Override
            public void onMessage(byte[] message) {
                mEngineIoWebSocket.emit("message", (Object) message);
            }
        });

        mEngineIoServer.handleWebSocket(mEngineIoWebSocket);
    }

    @Override
    public void onClose(Session session, CloseReason closeReason) {
        super.onClose(session, closeReason);

        mEngineIoWebSocket.emit("close");
        mSession = null;
    }

    @Override
    public void onError(Session session, Throwable thr) {
        super.onError(session, thr);

        mEngineIoWebSocket.emit("error", "unknown error", thr.getMessage());
    }

    private class EngineIoWebSocketImpl extends EngineIoWebSocket {

        private RemoteEndpoint.Basic mBasic;

        EngineIoWebSocketImpl() {
            mBasic = mSession.getBasicRemote();
        }

        @Override
        public Map<String, String> getQuery() {
            return mQuery;
        }

        @Override
        public void write(String message) throws IOException {
            mBasic.sendText(message);
        }

        @Override
        public void write(byte[] message) throws IOException {
            mBasic.sendBinary(ByteBuffer.wrap(message));
        }

        @Override
        public void close() {
            try {
                mSession.close();
            } catch (IOException ignore) {
            }
        }
    }
}

@trinopoty
Copy link
Collaborator

Seems like the server isn't handling websocket connections.
Can you make sure ApplicationServerConfig.getEndpointConfigs is called and the endpoint is registered properly?

@trinopoty
Copy link
Collaborator

Also, enable async support on the servlet to enable delayed responses and not have too many requests hitting the server.

@jeevaengg21
Copy link
Author

ApplicationServerConfig.getEndpointConfigs is called and entered inside below block

public void onOpen(Session session, EndpointConfig endpointConfig)

But Front doesn't receive a message emitted from server.

Enabled async support on the servlet to enable delayed responses, but still, UI is trying to establish the connection.

Browser:
image

Server:
image

@jeevaengg21
Copy link
Author

@trinopoty One More point for your analysis,

public final class EngineIoEndpoint extends Endpoint {

    private Session mSession;
    private Map<String, String> mQuery;
    private EngineIoWebSocket mEngineIoWebSocket;

    private EngineIoServer mEngineIoServer; // The engine.io server instance

As per the document, mEngineIoServer is declared but not initialized so it end-up in null pointer exception inside onOpen method block. So now I have initialized it, but still the same problem occurs no message received at front and connection keep on requested from UI
Before:
private EngineIoServer mEngineIoServer;
Now
private EngineIoServer mEngineIoServer = new EngineIoServer(); // The engine.io server instance

@trinopoty
Copy link
Collaborator

Ah I see. You have to get it in from somewhere that you initialized.
The documentation cannot know where you want to get it from so it's just there as an example.
Additionally, putting new EngineIoServer() creates a new instance of the server and I don't think that's what you would want to do.

@jeevaengg21
Copy link
Author

Ya, exactly its not helping to meet my use case, so what would be exact implementation to kick-start the process :)

@trinopoty
Copy link
Collaborator

One possible solution is to declare mEngineIoServer as public static in EngineIoServlet and get it from there.

@jeevaengg21
Copy link
Author

Ok Sure, let try that too and post the update.

I appreciate your very quick response. Thanks 👍

@jeevaengg21
Copy link
Author

@trinopoty That worked ! referring the mEngineIoServer of EngineIoServlet resolved the connection retry issue 👍 But still message not received from the server ( EngineIoServlet / EngineIoEndpoint ).

Now, i try to emit the message from onOpen block of EngineIoEndpoint to notify the client with a welcome message (for example), and it end up in NmberFormatException .

mEngineIoWebSocket.emit("message","Welcome ! connection openend");

image

@jeevaengg21
Copy link
Author

jeevaengg21 commented Dec 19, 2019

@trinopoty One more input, I just put sysout inside the service code blog, it fired 3 times for a single connection from front end, but the onOpen block of EngineIoEndpoint is fired once. This is something odd and when i try open another session from front end, that new session gets back 3 messages from the server, whereas first session still didn't any response from server

@Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException {

System.out.println("mEngineIoServer?? " + mEngineIoServer);

image

@trinopoty
Copy link
Collaborator

trinopoty commented Dec 19, 2019

You have mEngineIoServer.on("connection", new Emitter.Listener() { in your service method. This will add a listener every time a connection is made.
Move that bit into a your constructor.

@trinopoty
Copy link
Collaborator

Also, you can't send a message from the onOpen method of EngineIoEndpoint.
The handshake isn't complete at that point and so, no connection is actually established for you to send data over.

@jeevaengg21
Copy link
Author

jeevaengg21 commented Dec 20, 2019

After moved the connection listener to postconstruct layer everything in order now. Thanks.

Herewith attached the working sample which could be helpful for someone. Also, request you update the document section so that you save your valuable time.

engine.io.zip

@jeevaengg21
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants