DEV Community

tang
tang

Posted on • Updated on

build log: sentiment-chat pt3 | Implementing socket.io

This is less about the overall project, and more about getting socket.io communicating from my client to the server. It's gonna be a very close-in, nose-to-the-grindstone type of deal.

Most of the guides that exist will tell you how to send and receive data, but aren't exactly clear on what goes where, so I'll be providing excessive code snippets as we walk through the project.

We're working with a Node/Express backend, and the setup for this is kind of particular. Here's what setting up socketio looks like on my server, with Express.

Server

const express = require('express');
const app = express();
const server = require ('http').createServer(app);
const io = require('socket.io')(server);
//...
server.listen(3000, ()=>{console.log('listening on 3000'})

The express/"app" setup works like any other Node/Express setup. However, it gets a little weirder on the next two lines. I'm not completely sure how they work, but it seems that we're creating some sort of http server, giving it our app as an argument, and creating some sort of a socketio connection, giving it server as an argument.

Instead of invoking listen as a method on our app, it's invoked on our server, which I'm assuming is what lets us take socket connections in addition to the rest of our normal server functionality.

I'm gonna assume that you know how to do the usual stuff. Serving routes and so on. So we'll skip that part. Instead, now that we've got the io thing, we'll listen for a connection.

const express = require('express');
const app = express();
const server = require ('http').createServer(app);
const io = require('socket.io')(server);

io.on('connection', (socket)=>{
  console.log('user connected');
})

server.listen(3000, ()=>{console.log('listening on 3000'})

Client

That's the server, for now. Let's have a look at the client.

In our index.html, we need to add the following tag: <script src="/socket.io/socket.io.js"></script>. This is, of course, a relative filepath. We don't set it up ourselves, but, rather, it's provided to us by using socket.io in our server.

With this script tag as a given, we can start doing stuff in our frontend to connect. Ignoring any other sort of frontend functionality, let's imagine we literally just have a javscript file that will connect to our server. It'd look like this:

const socket = io()

io is provided to us by the script tag we inserted.

Now, when we launch our server and load our page in our browser, it'll trigger the io.on('connection', ...) listener and log 'user connected' to our server's console.

Now that we've got a connection and have confirmed that the client and server are communicating, we'll need to listen for other events.

Server (again)

So, let's get back to the server. We're listening for a connection, and firing off a callback once that connection is established.

const express = require('express');
const app = express();
const server = require ('http').createServer(app);
const io = require('socket.io')(server);

io.on('connection', (socket)=>{
  console.log('user connected');
})

server.listen(3000, ()=>{console.log('listening on 3000'})

What tripped me up is that I thought we could just add another io.on, similar to the event listener for 'connection'. However, we actually need to add other event listeners inside of the callback for our io.on('connection').

You may have noticed that we're taking a parameter called socket inside of our callback. That will actually provide us with an object with an on method on it, which we'll use to create another event listener. We can name our listener anything we want. We'll call it 'hello'.

const express = require('express');
const app = express();
const server = require ('http').createServer(app);
const io = require('socket.io')(server);

io.on('connection', (socket)=>{
  console.log('user connected');
  socket.on('hello', (data)=>{
    console.log('data received:', data)
  }
})

server.listen(3000, ()=>{console.log('listening on 3000'})

similar to the io.on, socket.on takes two arguments. The first is a a string that corresponds to an event to listen for. The second is a callback function. In this case, we expect the callback to get some data that we'll send from our frontend.

Now, let's get back to the frontend.

frontend (again)

Here's where we left off. io opens up a connection to our backend, which lives on the socket object.

const socket = io();

Let's do a little hello world. Sending data from the frontend is fairly easy. Now that we have socket, we can just do this:

const socket = io();

socket.emit('hello', 'hi from the frontend!');

The first argument of socket.emit is, of course, the name of the event. Our backend is listening for a 'hello', so our frontend is sending out that 'hello'. The second argument is data that we're sending out, corresponding to the event.

Tying it all together

So, when our frontend fires

socket.emit('hello', 'hi from the frontend!');

our backend catches it here:

io.on('connection', (socket)=>{
  console.log('user connected');
  socket.on('hello', (data)=>{
    console.log('data received:', data)
  }
}

Our server receives the 'hello' event, and takes 'hi from the frontend' as data in our callback function, and, finally, logs data received: 'hi from the frontend' to the console.

With this, we can send messages from our client to the server. Next, we'll need to have our clients listen for messages from the server. I'm hoping to get that done tomorrow, then spend the rest of the week doing UI/UX stuff. Thanks for reading along!

Top comments (0)