DEV Community

Daniel Warren
Daniel Warren

Posted on

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()
Enter fullscreen mode Exit fullscreen mode

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:${port}`)
  }
})
Enter fullscreen mode Exit fullscreen mode

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:${port}`)
  }
})

const io = require('socket.io')(server); 

// Sets up the connection
io.on('connection', (socket) => {  
  console.log('a user connected');
})
Enter fullscreen mode Exit fullscreen mode

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:${port}`)
  }
})

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")
    })
})
Enter fullscreen mode Exit fullscreen mode

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:${port}`)
  }
})

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');
    })
})
Enter fullscreen mode Exit fullscreen mode

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')
Enter fullscreen mode Exit fullscreen mode

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
    })
Enter fullscreen mode Exit fullscreen mode

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
})
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)