Creating a Node.js Server/Client with Socket.IO & MySQL

Want to learn something new? Check out my most recent Egghead course:



Build a Twelve-Factor Node.js App with Docker - WATCH NOW on Egghead.io!

Cheers -Mark

Thu, 11/07/2013 - 10:08

Submitted by markoshust Thu, 11/07/2013 - 10:08

Personally, I find Node.js to be completely fascinating. It's a direct lineage of Atwood's Law, that "any application that can be written in JavaScript, will eventually be written in JavaScript". Even the server. This, my friends, in a day of jQuery and JSON starting to rule the world, is a beautiful thing.

A real nice Node community is forming (and for that matter, has already formed), and tutorials are starting to pop up on the internet of how to write a server/client with Node. I'd like to give you my take on that, starting with a MySQL-supported writeup for all those other LAMP guys out there wanting to start to dabble in Node, and even more specifically it's websockets implementation, Socket.IO.

Get the Required NPM's

Node works with it's own repository of packages called npm (node package manager), sort of like Ubuntu's apt repository. Let's go ahead and install our required packages for the server, and use homebrew to install node:

brew install node
npm install socket.io mysql

Create the Node.js Server

Some tuts start on creating a client first, but I like to start with the server so that there aren't broken commands running at any given time.

We'll start by creating our MySQL database. This tutorial assumes that you have a 'root' username with no password set.

mysql -u root -e 'CREATE DATABASE node'

Then we'll populate it with some data. This should just be considered the base data that we'll start with (instead of having no records):

mysql -u root node -e 'CREATE TABLE notes (id INT(8) NOT NULL AUTO_INCREMENT, note VARCHAR(50) NOT NULL, PRIMARY KEY (id))'
mysql -u root node -e 'INSERT INTO notes (note) VALUES ("This is a test!", "This is another test...", "And, yet again, another...")'

Let's now go ahead and create a folder to house all of our files:

mkdir node
cd node

Now we want to create our server.js file and put in our backend code to run the server. Check out the comments for some basic understanding of what's going on; it's all really pretty simple.

var mysql = require('mysql')
// Let’s make node/socketio listen on port 3000
var io = require('socket.io').listen(3000)
// Define our db creds
var db = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    database: 'node'
})

// Log any errors connected to the db
db.connect(function(err){
    if (err) console.log(err)
})

// Define/initialize our global vars
var notes = []
var isInitNotes = false
var socketCount = 0

io.sockets.on('connection', function(socket){
    // Socket has connected, increase socket count
    socketCount++
    // Let all sockets know how many are connected
    io.sockets.emit('users connected', socketCount)

    socket.on('disconnect', function() {
        // Decrease the socket count on a disconnect, emit
        socketCount--
        io.sockets.emit('users connected', socketCount)
    })

    socket.on('new note', function(data){
        // New note added, push to all sockets and insert into db
        notes.push(data)
        io.sockets.emit('new note', data)
        // Use node's db injection format to filter incoming data
        db.query('INSERT INTO notes (note) VALUES (?)', data.note)
    })

    // Check to see if initial query/notes are set
    if (! isInitNotes) {
        // Initial app start, run db query
        db.query('SELECT * FROM notes')
            .on('result', function(data){
                // Push results onto the notes array
                notes.push(data)
            })
            .on('end', function(){
                // Only emit notes after query has been completed
                socket.emit('initial notes', notes)
            })

        isInitNotes = true
    } else {
        // Initial notes already exist, send out
        socket.emit('initial notes', notes)
    }
})

At this point you can run your node server:

node server.js

and you should see the message output in terminal, "   info  - socket.io started". You can use Ctrl+C to stop the server at any time.

Setup the Client File

My guess is that you want some sort of web browser interaction with this server (why you are on this page, eh?), so let's create the client-side file to connect to this socket.

Call me lazy or just biased, but I don't even think to begin any JavaScript app without jQuery. We'll use the Google-CDN hosted jQuery file, and the socket.io.js file is automatically loaded from your running node server.

Create a our client-side html file which will load jQuery, socket.io, as well as our client-side code. We'll name this index.html.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://localhost:3000/socket.io/socket.io.js"></script>
<script>
$(document).ready(function(){
    // Connect to our node/websockets server
    var socket = io.connect('http://localhost:3000');

    // Initial set of notes, loop through and add to list
    socket.on('initial notes', function(data){
        var html = ''
        for (var i = 0; i < data.length; i++){
            // We store html as a var then add to DOM after for efficiency
            html += '<li>' + data[i].note + '</li>'
        }
        $('#notes').html(html)
    })

    // New note emitted, add it to our list of current notes
    socket.on('new note', function(data){
        $('#notes').append('<li>' + data.note + '</li>')
    })

    // New socket connected, display new count on page
    socket.on('users connected', function(data){
        $('#usersConnected').html('Users connected: ' + data)
    })

    // Add a new (random) note, emit to server to let others know
    $('#newNote').click(function(){
        var newNote = 'This is a random ' + (Math.floor(Math.random() * 100) + 1)  + ' note'
        socket.emit('new note', {note: newNote})
    })
})
</script>
<ul id="notes"></ul>
<div id="usersConnected"></div>
<div id="newNote">Create a new note</div>

Open the index.html file in a web browser, and you should now see our MySQL database records! Bam! I didn't go too much into detail in this article about what the file does, but the documentation speaks for itself. Read, analyze, code and understand :)

You'll see something like the following in your node server logs in your terminal window:

   debug - served static content /socket.io.js
   debug - client authorized
   info  - handshake authorized 8yYA5wvw2ItTPZ2GHoUD
   debug - setting request GET /socket.io/1/websocket/8yYA5wvw2ItTPZ2GHoUD
   debug - set heartbeat interval for client 8yYA5wvw2ItTPZ2GHoUD
   debug - client authorized for 
   debug - websocket writing 1::
   debug - websocket writing 5:::{"name":"users connected","args":[1]}
   debug - websocket writing 5:::{"name":"initial notes","args":[[{"id":1,"note":"This is a test!"},{"id":2,"note":"This is another test..."},{"id":3,"note":"And, yet again, another..."}]]}

Node's really nice verbose logging really tells you everything that is going on.

Test with Multiple Browser Windows

You can now open up index.html in multiple browser windows. Every new window should connect a new socket, thus incrementating the "Users connected" part of the screen... in *each* browser window, instantaneously. Add a new note in one browser window, adds it to all other browser windows (each a socket), instantly.

    debug - websocket writing 5:::{"name":"new note","args":[{"note":"This is a random 59 note"}]}

Appreicate the magic of node.js. Hopefully this helps demystify some of the misunderstandings of node and really gives you a brief understanding of how Node.js, Socket.IO and MySQL can be setup to provide near-instantanenous bidirectional communication.

Comments

goooooooooooood job continue... video tutorial :P

Hi Mark, When I try to run the server.js code the following error is occurred. C:\Program Files (x86)\nodejs\node_modules>node server.js info - socket.io started { [Error: connect ECONNREFUSED] code: 'ECONNREFUSED', errno: 'ECONNREFUSED', syscall: 'connect', fatal: true } Please help me to short out this bug. Thanks in advance Chandan

Hi Mark, After change made which was suggested by you the error is. Error: connect ECONNREFUSED in: client.query('CREATE DATABASE mynode_db', function(err) { if (err) { throw err; } }); console.log('database mynode_db is created.'); client.query('USE mynode_db'); can you please help me how to solve it. If required i will send you the source. Thanks Chandan

That's an error in mysql or whatever other database you are using. Try connecting to that database from terminal/console to diagnose further what the problem is...