0
votes

I am having trouble tracking down why my emits from my react client app are not getting to a localhost socket server. I am using a forked copy of PuppyJS that I modified to receive client events (https://github.com/BlackConure/puppyjs) via a socket.

I can us the Apic Chrome browser extension and connect to and send/receive messages to the server side just fine via web sockets, but when I try to connect via my client application in React, the connect seems to work, but the emit does nothing.

I have enabled localstorage.DEBUG='*' on a client side and it does not display anything happening with socket.io. I also started chrome with --disable-web-security to eliminate the possibility of a CORS issue; so all indications are that the issue is with my client setup.

Here is the configuration:

Just to be sure that the socket wasn't trying to re-use the existing (3006) connection, I also tried a forceNew. Still doesn't work.

var socket = io.connect('ws://localhost:3000', {
        path: '/ws',
        transports: [ 'websocket' ],
        forceNew: true
    });

    console.log(socket);

    socket.on('connect', function() {
        alert('connect');
    });

    socket.on('event', function(data) {
        alert('event');
        console.log(data);
    });

    socket.on('disconnect', function() {
        alert('disconnect');
    });

    socket.on('error', function(data) {
        console.log(data || 'error');
    });

    socket.on('connect_failed', function(data) {
        console.log(data || 'connect_failed');
    });

    socket.emit('LOGIN', 'Testing 123');
    newstate.socket = socket;
    return newstate;

Even though on the server side, I get a connect from my client application, it never seems to get to emit.

When I inspect the socket object, io.readyState says opening; so I thought something must be going on with the response from the server. I did a RawCap & Wireshark dump and found that the client received the HTTP 101 Switching Protocols response (same as in Apic); but nothing happens after that.

I traced the emit, and it is throwing the LOGIN into the request buffer (since connected=false), which I am assuming is because it is not in a readyState.

This made no sense, so I started up a simple NodeJS server using Socket.IO as the server, and it all works fine!

Does this mean that Socket.IO and WebSockets are not compatible or did I do something dumb on my part? I thought Socket.io was supposed to be able to handle different protocols. David Walsh's article (https://davidwalsh.name/websocket) states:

Socket.IO simplifies the WebSocket API and unifies the APIs of its fallback transports. Transports include:

  • WebSocket
  • Flash Socket
  • AJAX
  • long-polling AJAX
  • multipart streaming
  • IFrame
  • JSONP polling

Am I missing something? If these are not compatible, does that mean we now have to code differently depending on the communication layer?

1
socket.io implements an own protocol on top of these transports. You always need the server and client to use it. Read here how to use the server implementation of socket.io. If you want plain websockets you can also just use the WebSocket API. But then you e.g. have to implement your own subscribe mechanism on top of that and you have no intelligent fallback strategies like socket.io has for unsupported clients. - trixn
@trixn I am aware of the documentation and how to set up a client and server using socket.io, but I thought at least at the socket level you would have some consistency. Sure, you need to align with the messaging protocol between the server and client, but I thought the basic connect/send/receive was covered by Socket.IO, especially considering it handles multiple transports. - user3072517
I suppose that the socket.io client expects a lot more from the server to respond with other then just an HTTP 101 to get into the ready state and being able to exchange messages. But this requires an understanding of the internals of the socket.io protocol. You could make the socket.io server communicate with the client and inspect that with wireshark (or just in the chrome network tab). I guess there is a lot more happening that you'd expect. - trixn
I did a rawcap and wireshark and they responded exactly the same...the only different was the websocket key they returned. That was different between the two, but I assumed that was more about a unique token than an identification of what the connection was made with. - user3072517

1 Answers

1
votes

Does this mean that Socket.IO and WebSockets are not compatible or did I do something dumb on my part? I thought Socket.io was supposed to be able to handle different protocols.

Socket.io operates on top of websockets. It's like you are asking if a phone call (websockets) and japanese (socket.io) are compatible. You can't answer that because these are two different layers of communication. So just because the socket.io-client uses websockets to communicate with the server that does not mean he can exchange messages with a server that only knows how to establish a websocket connection (phone call) without being able to speak the socket.io protocol (japanese) over it.

What you may want to use is the browsers native WebSocket API which already provides an abstraction to establish a connection as well as sending/receiving messages.

Of course then you would have to implement a reconnecting and retrying strategy as well as fallback transports yourself if you need that for your app. That is what socket.io provides out of the box.