We are going to take a look at Socket.IO first.
It is because Socket.IO provides enterprise-grade WebSocket, where a lot of implementation details have been taken care of.
Set up working environment
As we have described in Exploring Socket.IO in a React Working Environment, the Socket.IO example is built in the Create React App environment.
npx create-react-app react-socket
In the working environment, we need to have one client and one server to communicate with each other. To simplify the task, we set up both the client and the server in the same repository.
Install the server package:
npm i socket.io.
Install the client package:
npm i socket.io-client.
package.json includes two extra packages in
Set up client
We create a user interface that has one button,
Click to request date from server. Clicking the button sends a Socket.IO request to the server. Upon receiving the request, the server responses with the current date. The client receives the server date and displays it on the screen.
src/App.js is modified to serve as a client:
Line 2 imports
A socket is initialized by calling
io('http://localhost:5000')(line 9), where the server runs upon
'http://localhost:5000'. If the client and server are hosted on the same origin, the URL does not need to be specified.
There are 3 special events to be listened:
'connect_error'which are listened at line 11, line 13, and line 17.
Line 21 listens to the custom event,
useRef (line 6) to generate a reference to keep the socket persistent (line 23). The client request is invoked by the button’s
onClick method (line 30).
The server response is saved to the state,
serverDataat line 21. And then, it is rendered by line 34.
socket.on(eventName, listener) is a method in the Socket.IO library. The socket connection listens to the specified event, and invokes the callback listener.
Set up server
We need to build a server for the client to talk to. An Express server is set up in
server/index.mjs. In the following code, an HTTP wrapper is used since the pure Express server creates a new HTTP server when
app.listen is invoked.
Line 8 creates an Express server.
Line 9 wraps the server with HTTP.
Line 10 initializes
io with the HTTP wrapper.
Line 11 reads the port from the environment variable. If it is not set, the default value is 5000.
Lines 13–15 serve the production web pages, which are generated by
npm run build.
Line 17 listens to the builtin event,
'connection' and sets up other listeners.
Lines 20–26 listen to the custom event,
'requestDate'. Upon receiving the event, it calls the server date (line 21). It emits the date on the event,
'responseDate'. There is no need to run
JSON.stringify() on the content to be sent, as it will be done automatically. For non-serializable objects, such as Map and Set, they must be manually serialized.
Line 28 listens to the builtin event,
'disconnect' and prints out the message.
Line 31 starts the HTTP server at the specified port.
Run the server by
node server/index.mjs. Clicking the button on the user interface shows the server date.
In the Socket.IO example, we have printed out many debug information. In fact, it is not necessary. We can use the Network panel to inspect the socket communication. The example is running on Chrome, but it works similarly on other browsers.
Open the Network panel. The following is the recommended process for analyzing:
- Check the
Preserve logcheckbox to save requests across page loads.
- Check the
Disable cachecheckbox to emulate the first-time user experience.
- Click the clear button to clear all requests from the requests table.
Click the button for a few times.
There are a few requests in the requests table, but there is only one
websocket connection. Instead of viewing
All requests, we can press the button to filter with
WS (WebSocket) only.
Click on the WebSocket request, and we can view all socket communications.
Here is the Socket.IO’s message definitions:
- 0 open: Sent from the server when a new transport is opened (recheck).
- 1 close: Request the close of this transport but does not shutdown the connection itself.
- 2 ping: Probe request is sent.
- 3 pong: Probe request is responded.
- 4 message: The actual message is sent.
- 5 upgrade: Socket.IO tests whether the browser supports WebSocket. If yes, it is upgraded to WebSocket. Otherwise, it stays HTTP long-polling.
- 6 noop: Used primarily to force a poll cycle when an incoming WebSocket connection is received.
The above screenshot shows the flow: The client sends
2probeand the server responds with
3probe. Then the client sends a bunch of
42 messages, where the custom event is
'requestDate'and the message is
'need date'. Upon receiving each custom event, the server responds with a
42 message, where the custom event is
'responseDate', and the message is the server date. When the client is idle, the server pings with
2and the client pongs back
With these detailed information, it becomes straightforward to analyze the socket communication.