Real time client-server communication with Socket.IO
A guide with real use cases examples
Have you ever needed to create an application that needs a real time client-server communication? In this article, we are going to help you doing that using the Socket.IO framework, including real use cases examples. Let's go?
What we are used to use
Probably every iOS developer have already used some type of request to consult some information on the internet accessing it with some API. One way to implement these kind on request is using an URLSession. In this kind of communication, the client requests the server and always wait for a server response, as it is shown on the following example:
Actually, this type of client-server communication can handle most of the applications that needs to request some specific information. But have you ever had to deal with a situation where the server would need to request the client at any moment? To update some data on the client app or change dynamically some client app property? These kind of situations needs a bidirectional communication, and Socket can help you with that.
Motivations
The bidirectional communication enables the client to request the server and vice versa and this is possible with Socket communication. This is an example of how this request flows works:
This type of communication can be very important in some applications and depending on the project, in some cases it could be a primordial feature. These are some examples that uses Socket:
- Real time coordinate/location sharing (available in this tutorial);
- Chat (available in this tutorial);
- Login/Validation with QRCode (available in this tutorial);
- Games;
- Financial market graphs;
- Any other kind of App that needs a real time update.
Socket communication works in a different way of those common requests that we are used to. It allows both the connected parts to communicate between themselves. Once initialized, both client and server can listen and speak messages.
What is Socket.IO?
Socket.IO is a framework that makes it easy to implement Socket and the available for iOS, Android, back-end and front-end. In this article you will find some code in Swift (iOS) and Javascript (Web) for implementing the client and NodeJS for implementing the back-end.
Serverside communication to clients
Every server that implements socket has a list of connected sockets and every client has a Socket ID. That's the way that servers can select which socket clients are going to receive some message. It's possible that a server selects only one ID of a specific socket client for sending a message or a group of specific IDs. A server with socket can also send a message for all the socket clients connected at some moment.
How it works
Socket.IO has basically two methods: one for emitting messages and another for listening messages. Both of these methods receive some parameters, an event and the data. In the following example there is a socket emitting and event called "message" and the data is "content".
In this case, event's name is "message" and the content of the message is the text "content". The example below listen to the event above using the on method:
In this example, when the listening method listens to "message", a closure will be executed receiving the data parameter that has all the data included in this message, in this case "content".
Defaults events
This framework has some default events that will always be called for any socket connection and can be used to receive some kind of feedback on the client or server application. Here is some of the most used examples of default events:
Using Socket.IO
Follow the steps below to create your first iOS App with Socket! 😃
Installing Socket.IO in an iOS App
It's possible to install Socket.IO with CocoaPods, Carthage and Swift Package Manger. In this article example we are going to use Swift Package Manger. Follow the steps below:
- Create a new Xcode project (File -> New -> Project).
- Select iOS e Single View App e click Next.
- Type a name for your project and click Next.
- Go to File -> Swift Packages -> Add Package Dependency…
- Paste o link https://github.com/socketio/socket.io-client-swift.git, and click Next.
- Select Branch: master and click Next.
- Click Finish.
Use case examples
These are some examples of use cases that benefit from using Socket:
- Real time coordinate/location sharing
An implementation that uses coordinates (2 values, one for x and other for y) can be used in different contexts. Here we are going to understand some examples that benefit from real time coordinate sharing. An example of an element position:
Another exemple is the app below that updates a pin on a map representing a geolocation of some device moving:
In this case, the simulator on the right represents the device that is moving (Simulator -> Debug -> Location -> Freeway Drive). This device sends information of the coordinate every-time it changes the location, and the server shares this information with all the other sockets connected. The simulator on the left receives the event with the coordinate and updates the position of a pin on the map.
The only difference between those tho examples is the UI implementation. Both uses the same socket implementation. The code below is a parser that is going to be used in the socket observer’s implementation.
The SocketParser class are going to be used to convert the data received from the socket events. The listeners returns Arrays of Any. In this case SocketParser converts this information to a generic type.
The SocketPosition struct represents the 2D coordinate, with the x and y values:
The protocol below is for the controller of the module to receive the information of the Socket class:
This is the way that our controller can be triggered when the socket connects and a new position is received.
SocketTutorialManager is the example of implementation of an Socket.IO client in Swift:
The SocketTutorialManager have a manager variable, one SocketManager that receives some configuration properties like the socket server URL. The log configuration property, makes the SocketManager show logs on the console when it is true.
In the SockeTutorialManager init, the method setupSocket() is called, it is going to initialize the socket (a SocketIOClient) variable, that is going to be used to emit and listen events. In the init we also have setupSocketEvents() being called, that configures the observers and socket events. After all the connect() method of SocketIOClient is called, and it makes the socket connect to the URL and starts the listening job and emit events.
The setupSocketEvents() function configures the event observers. The first observer added is an clientEvent .connect that is one of the default events. The second observer added is a custom that listen to "drawing" and inside the closure it uses the SocketParser to convert the Any array.
The socketChange(position: SocketPosition) converts the SocketPosition to a String:Any dictionary with x and y to represent the coordinate and emit the message with the emmit method, it sends a "drawing" event with the dictionary.
The stop() method should be called when the module is going to be ended. This method calls removeAllHandlers() do SocketIOClient that removes from memory all the framework observers.
The UI implementation
To implement an UI that changes an UI element position, it is possible to use the SocketPositionManagerDelegate protocol in the UIViewController. The code below shows an exemple of an element being moved:
In this case, the element variable represents a declared UIView added to the screen. This UIView is receiving and CGPoint that uses the value from the SocketPosition.
It's possible to implement moving pin inside a map using the same SocketPosition received. The x and y values of the SocketPosition can be used to initialize the CLLocationCoordinate2D and update the pin or zoom in a specific region.
In this case the screen variable represents an UIView that was previously declared and associated with the UIViewController’s view. This UIView already have a MKMapView that has a pin, which is going to have its location changed. The screen variable receives a CLLocationCoordinate2D that was initialized with the values from SocketPosition.
This same implementation can be used with any kind of app that uses coordinates. This can be useful inside online games, which have its objects being controlled by some other user.
Server Application
In this example, it’s possible to use the Socket.IO application available in this link. The intention of this project is to be a blackboard where users can draw at the same time so all the others users can see it.
This server app is also a great example, because it’s implementation is very simple, it only repass all the data received for all connected socket clients with the event “drawing”. If you want to try implementing the server, the following example is enough to run the app using NodeJS.
The constant io represents our access to the Socket.IO module. Line 33 has the initialization of the observer (using the on() method), that receives the onConnection function that executes every-time it receives the “connection” call. In NodeJS “connection” is the default event that is triggered when a connect is stablished.
The onConnection function is used to setup the initial configuration for the observers that are going to be active for that socket client. In this function, the “drawing” observer is created and receives a data that represent the data received in this event, this same variable is sent for broadcast with the same event name “drawing”. This broadcast emmit means that the server is going to emmit the event for all the socket clients connected, but will not send for the same socket that is emmiting the event.
As we can see, it’s possible to use this server for a lot of different tests because it only repass the data received for broadcast. For more details about this implementation access the this link.
2. Chat
This is a classic example that can be implemented using socket. In this example we are going to update a table of messages when the message is received by the socket client.
The following code represents the structure of the implementation for iOS:
This example implementation follows the same idea of the last example, but it has some new methods. One of the new methods is register(user), that emits an event with “add user” name with the name of the current user that wants to enter the chat and the method send(message) that emits an event called “new message” with the message content as data.
The main difference in this example is the implementation of the setupSocketEvents() method that configures lots of new events:
- “user joined” = receives the username of the connected user and the new total of user connected.
- “user left” = receives the username of the user that has disconnected and the new total of user thad still connected.
- “new message” = receives the username of the user that has sent a message and the content of the message sent.
- “typing” = receives the username of the user that is typing a message.
- “stop typing” = receives the username of the user that stopped typing.
Server Application
The server implementation has some new methods to repass the information about users and messages.
The variable numUsers represents the total of users inside the chat. This variable is updated with the “add user” and “disconnect” events. The method that “add user” triggers increment the integer number of the variable numUsers, and it also adds the username inside the respective socket connection used by the user to connect. The “add user” method also emits an event called “user joined” for broadcast, showing for all the other connected users which is the new total number of connected users in the chat and the username of the new user connected and emits the event “login” for the socket that just connected with the total number of user connected.
Important: The difference between emmit and broadcast is that broadcast sends the message for all connected sockets but not for itself and emmit only sends the event to the current socket that the method is called.
3. Login / QR Code Validation
The QR Code scan can be used inside lots of apps, as an extra login level, or the validation of some online operation.
At the left is a web client showing the QR Code and at the right we can see an iOS scanner reading and sending the message to the web client. In this example the socket implementation is only needed in the web client. This kind of application is actually very simple. The following step by step sequence shows how the process is made.
A sequence of steps is needed for this application to work, it all starts with the web client:
- Web client connects with the socket server;
- After connecting it receives the socket ID;
- Web page shows the socket ID using a QR Code (the string of the socket ID represented with a QRCode).
After that, the mobile client (iOS) follows the steps bellow:
- Reads the QR Code;
- Converts the QR Code to text (this is going to generate the string with the socked ID of the web client);
- Sends a request for the server with the socket ID and the message.
The server follow the steps bellow:
- Receives the request with the socket ID and the message;
- Converts the values received to string;
- Sends the message only for the socked specified.
At the end, the web client receives a message from the server and shows it.
Client App: iOS
The mobile app in this example do not need a socket implementation. The application just reads a QRCode and sends to the server, the scanned QRCode code string and the message using a simple POST request.
Client App: Web
When the web client is loaded, it connects to the server and receives the socket ID, and shows this ID in a QR Code format. In this example jQuery is used to help with the process inside the front-end. Here is an example of how the .html page looks like prepared to show the QR Code message:
This page has a div and 2 paragraphs. The QR Code message is going to be added inside the div with the “qrCodeImage” id, the socket id is going to be added inside the span with “qrCodeSocket” id and the received message from mobile client is going to be added inside the span with “qrCodeMessage” id. This page also have a span with “socketStatus” id to shows the status of the connection.
This page algo loads the “ClienteWeb.js” that configures the socket communication with the server. This is the script code:
The socket variable is initialized with the url of the current server (window.location.host).
Using jQuery, the function inside the ready method of $(document) is executed all the time that the page is reloaded. Inside this function the socket observers are declared.
The first observer added is the “connect” that observes the default event of a successful connection. This event execute some initial configurations, it changes the status text to “connect”, adds an image of the qrcode with the .qrCode method that receives the socket id of the client (socket.io.engine.id) and adds the same socket id inside the span “qrCodeSocket”.
The default observers “reconnecting” and “disconnected” only removed the qrCode image and socket id. The observer of the event “qrCodeMessage” receives the data with the text message sent from the mobile client and shows it inside the qrCodeMessage, executing a GIF animation and at the end it shows the QR Code again.
Server Application
The implementation of the server in this case needs a API route to receive the POST request and select the socket id specified to send the message. It can be implemented this way:
Line 11 has the “qrCodeMessage” event that is sent with the content of the received message, for only the specified socket client id (qrCode variable).
To use the io property is necessary to add it inside application, so it can be used at any time, it can be done like this:
And that’s it!! 🙌🏻😃
Conclusion
The idea of this post is to show how socket works and the possibilities with this technology with some practical app examples. As we can see it there are many applications that can benefit from using Socket.
If you have any doubt or suggestions, feel free to add a comment bellow or contact me. 😜