Comfortable Tube Sockets

January 26, 2018 0 Comments

Comfortable Tube Sockets

 

 


According to their website, "Socket.io enables real-time bidirectional event-based communication.” Unpacking this description, it essentially means a browser and server can have live information sent back and forth instantaneously to multiple users. In a chat application, when one user types a message and presses enter, the message travels to the server, and from the server, it’s sent out to all of the other users connected to the socket. I like to think about a socket as a tube from your browser to the server. You shoot information up the tube where it hits the server. At the server, it’s processed and copied, and sent back down all of the other open tubes and handled by the client.

Beyond chatting, sockets are used for all sorts of applications including document collaboration and multiplayer video games. In this tutorial, I’ll go over the basic concepts of a chat application. Because Socket.io can be used with almost any framework, I won’t go into any setup details, instead focusing on the main concepts. In addition, I won't cover setting up a package.json file or using npm install for dependencies. If you need more information on these subjects, see here for npm and here for package.json.

First we’ll start with server.js which will live in the root of your project. Start by adding the following dependencies and create a new Express app:

const express = require('express')
const socket = require('socket.io')
// open is for convenience
const open = require('open')
const app = express()

Next, we need to specify where to serve up our static files. This may change depending on the framework you use, but in my case, I'm serving up files from the public directory. Then we need to setup the server to listen on, in this case, port 8000, or whatever port you like:

const express = require('express')
const socket = require('socket.io')
const open = require('open')
const app = express()
const port = 8000 app.use(express.static('/public')) const server = app.listen(port, function(err) { if (err) { console.log(err) } else { open(http://localhost:</span><span class="si">${</span><span class="nx">port</span><span class="si">}</span><span class="sb">) }
})

Now that we have our Express server running, we need to listen for user connecting to a socket using io.on. A user connects, and the function says, oh, we have a new user.

const express = require('express')
const socket = require('socket.io')
const open = require('open')
const app = express()
const port = 8000 app.use(express.static('/public')) const server = app.listen(port, function(err) { if (err) { console.log(err) } else { open(http://localhost:</span><span class="si">${</span><span class="nx">port</span><span class="si">}</span><span class="sb">) }
}) const io = require('socket.io')(server); // Sets up the connection
io.on('connection', (socket) => { console.log('a user connected');
})

With this function, we can place different listeners inside that we will link up with the client side later. The first one will listen when the user sends a new message. We'll use socket.on which takes any name, but in our case, we'll simply call it 'chat', and a callback function. When our user presses send on a new message, the message is sent through the tube to where it is caught by our socket.on function.

Once we catch the message from the client, we use io.sockets.emit. This function takes the message and sends it down the tubes to all of the other open sockets:

const express = require('express')
const socket = require('socket.io')
const open = require('open')
const app = express()
const port = 8000 app.use(express.static('/public')) const server = app.listen(port, function(err) { if (err) { console.log(err) } else { open(http://localhost:</span><span class="si">${</span><span class="nx">port</span><span class="si">}</span><span class="sb">) }
}) const io = require('socket.io')(server); io.on('connection', (socket) => { console.log('a user connected') socket.on('chat', (data) => { // Emits chat message to all open sockets io.sockets.emit('chat', data) console.log("Chat emitted from server") })
})

You can add as many listeners as you'd like, but for this tutorial, we'll keep it simple and add one more that sends a message to the console when a user disconnects:

const express = require('express')
const socket = require('socket.io')
const open = require('open')
const app = express()
const port = 8000 app.use(express.static('/public')) const server = app.listen(port, function(err) { if (err) { console.log(err) } else { open(http://localhost:</span><span class="si">${</span><span class="nx">port</span><span class="si">}</span><span class="sb">) }
}) const io = require('socket.io')(server); io.on('connection', (socket) => { console.log('a user connected') socket.on('chat', (data) => { io.sockets.emit('chat', data) console.log("Chat emitted from server") }) // Disconnects socket.on('disconnect', () => { console.log('user disconnected'); })
})

Now it's time to move to our client side which, in our case, will run in the public folder as client.js.

First, let's wire up our client side and server by using socket.io-client:

const io = require('socket.io-client') const socket = io('http://localhost:8000')

Then we'll set up an event listener for the send button click. I will leave this code vague since it depends on how you wire this up in your own project. You may simply have an event listener on the button in vanilla JS or you may be using something like React. Beyond what you choose, you'll want to have the following code inside that sends the message up the tubes with any other relevant information (like username, date, etc.):

// Inside your event listener socket.emit('chat', { message: message, username: username })

Once the send button is clicked, Socket.io emits the chat to the server where it's caught and sent to every open socket. The next step is to setup the 'catcher' of that data being sent back from the server. We do this using socket.on which listens for any chats being sent back down all the tubes:

socket.on('chat', (data) => { console.log("Received from server: " + data) // Do something with the data
})

You can decide how to handle the data once received. You may want to populate a div using something like document.getElementById('messages').innerHTML = "<p>" + data.message + "</p>" or if you're using something like React, you can update the state with the new message.

We have barely scratched the surface on Socket.io, but understanding the basics allowed me to learn more about sockets as the concept was hard to grasp at first.


Tag cloud