Sockets enable inter application communication over a network. Most networking software that you use, web browsers, web servers, SSH clients, email applications leverage sockets to communicate with remote applications.
WebSockets are a relatively new protocol that is supported by browsers and web servers that facilitate more real time connectivity between client and server than HTTP alone has traditionally supported. WebSockets different only a bit from regular sockets so anything that supports regular socket communication can be made to support WebSockets. The benefit to going this direction is that you can write a server side application that uses WebSockets and every client under the sun should be able to work with it. Browser, Java Applet, Android app, iOS app, desktop application, PhoneGap application and so on.
Node.js is a JavaScript platform for creating applications. JavaScript is a nice way to create synchronous socket based server applications. I like to use a library called Socket.IO with Node.js.
You can run a Node.js server on your computer and access it from the local network (as long as the network you are on allows it). Simply download Node.js, write your server and run it.
In order to make a server written with Node.js and Socket.IO available to clients on the regular internet, it needs to be run on a server that is accessible to clients on the public internet. There are a variety of cloud based services for running Node.js servers but one that I like is Digital Ocean.
In order to get started, with Digital Ocean, you'll need to create an account.
After that, you can go ahead and create a "droplet". A "droplet" is Digital Ocean's term for a VPS. After coming up with a hostname, I would choose the smallest size, an appropriate region (one close to you, perhaps), and then in "Select image" go to the second tab, "Applications" and choose "node-v0.10.30 on Ubuntu 14.04" (the version numbers may change) and click "Create Droplet".
Digital Ocean will email you a password to use with the default "root" account. In order to do anything, you first have to login to the newly created server via the command line to change your password. To do so, open up Terminal on your Mac (or use PuTTY if you are on a PC). To connect on from the Terminal app on the Mac, you type the following:
ssh root@ip_address(The "ip_address" is in the email you get from Digital Ocean.) You will be prompted to enter the password (which is also from the email) and then prompted to enter it again to change it. Go ahead and change it to something you will remember but sufficiently complex that it will be difficult for hackers.
Once you have done that, we can move on although it is probably a good idea to keep the terminal open as we'll be using it again shortly.
In order to upload to your server, we need to use a tool that will allow us to connect via SSH to transfer the files. I have found that Cyberduck and Fetch (available for free from NYU's ITD department) are good tools.
To connect, choose "SFTP (SSH File Transfer Protocol)", under "Server" use the IP address emailed to you by Digital Ocean. The "username" is "root" and the "password" is what you just created in Terminal.
Here is a quick example (from http://itp.nyu.edu/~sve204/liveweb_fall2013/week3.html)
// HTTP Portion var http = require('http'); var fs = require('fs'); // Using the filesystem module var httpServer = http.createServer(requestHandler); httpServer.listen(8080); // Any normal http request function requestHandler(req, res) { // Read index.html fs.readFile(__dirname + '/index.html', // Callback function for reading function (err, data) { // if there is an error if (err) { res.writeHead(500); return res.end('Error loading index.html'); } // Otherwise, send the data, the contents of the file res.writeHead(200); res.end(data); } ); } // WebSocket Portion // WebSockets work with the HTTP server var io = require('socket.io').listen(httpServer); // Register a callback function to run when we have an individual connection // This is run for each individual user that connects io.sockets.on('connection', // We are given a websocket object in our function function (socket) { console.log("We have a new client: " + socket.id); // When this user "send" from clientside javascript, we get a "message" // client side: socket.send("the message"); or socket.emit('message', "the message"); socket.on('message', // Run this function when a message is sent function (data) { console.log("message: " + data); // Call "broadcast" to send it to all clients (except sender), this is equal to // socket.broadcast.emit('message', data); socket.broadcast.send(data); // To all clients, on io.sockets instead // io.sockets.emit('message', "this goes to everyone"); } ); // When this user emits, client side: socket.emit('otherevent',some data); socket.on('otherevent', function(data) { // Data comes in as whatever was sent, including objects console.log("Received: 'otherevent' " + data); }); socket.on('disconnect', function() { console.log("Client has disconnected"); }); } );Save this file as whatever.js and upload it to a new directory on your server.
<html> <head> <script src="/socket.io/socket.io.js"></script> <script> var socket = io.connect('http://SERVER_NAME:8080/'); socket.on('connect', function() { console.log("Connected"); }); // Receive a message socket.on('message', function(data) { console.log("Got: " + data); document.getElementById('messages').innerHTML += data; }); // Receive from any event socket.on('otherevent', function (data) { console.log(data); }); var sendmessage = function() { var message = document.getElementById('message').value; console.log("Sending: " + message); // Send a messaage socket.send(message); }; var sendother = function() { var othermessage = document.getElementById('message').value; console.log("sending: " + othermessage); // Send any kind of data with a custom event //socket.emit('otherevent',{ othermessage: othermessage }); socket.emit('otherevent', othermessage); }; </script> </head> <body> <div id="messages"> No Messages Yet </div> <div> <input type="text" id="message" name="message"> <input type="button" value="message" onclick="sendmessage();"> <input type="button" value="other" onclick="sendother();"> </div> </body> </html>
More documentation and examples: http://socket.io/
As you can see, sockets programming is very event driven (as is JavaScript). When a message comes in a function is called to handle that message.
Of course, since websockets are JavaScript based, they just work in our PhoneGap applications.
Here is an example PhoneGap application which sends acceleromter data from the phone
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" /> <title>Hello World</title> <script type="text/javascript" src="cordova.js"></script> <!-- Use Socket.IO from the CDN or locally --> <script src="https://cdn.socket.io/socket.io-1.3.4.js"></script> <script type="text/javascript"> var socket = io.connect('http://SERVER_IP:8080/'); socket.on('connect', function() { console.log("Connected"); window.addEventListener('devicemotion', ondevicemotion, false); }); // Receive a message socket.on('message', function(data) { console.log("Got: " + data); }); function ondevicemotion(e) { var x = e.acceleration.x; var y = e.acceleration.y; var z = e.acceleration.z; console.log(x + " " + y + " " + z); var message = {x: x, y: y, z: z}; socket.send(message); } </script> </head> <body> </body> </html>and the corresponding server:
// HTTP Portion var http = require('http'); var fs = require('fs'); // Using the filesystem module var httpServer = http.createServer(requestHandler); httpServer.listen(8080); // Any normal http request function requestHandler(req, res) { // Read index.html fs.readFile(__dirname + '/screen.html', // Callback function for reading function (err, data) { // if there is an error if (err) { res.writeHead(500); return res.end('Error loading screen.html'); } // Otherwise, send the data, the contents of the file res.writeHead(200); res.end(data); } ); } // WebSocket Portion // WebSockets work with the HTTP server var io = require('socket.io').listen(httpServer); // Register a callback function to run when we have an individual connection // This is run for each individual user that connects io.sockets.on('connection', // We are given a websocket object in our function function (socket) { console.log("We have a new client: " + socket.id); // When this user "send" from clientside javascript, we get a "message" // client side: socket.send("the message"); or socket.emit('message', "the message"); socket.on('message', // Run this function when a message is sent function (data) { console.log("message: " + data.x + " " + data.y + " " + data.z); // Call "broadcast" to send it to all clients (except sender), this is equal to // socket.broadcast.emit('message', data); socket.broadcast.send(data); // To all clients, on io.sockets instead // io.sockets.emit('message', "this goes to everyone"); } ); socket.on('disconnect', function() { console.log("Client has disconnected"); }); } );Finally, here is a screen.html file which can be used to receive the events and visualize them. It uses p5.js and Socket.io.
<html> <head> <script language="javascript" type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/p5.js/0.3.11/p5.min.js"></script> <script src="https://cdn.socket.io/socket.io-1.3.4.js"></script> <script type="text/javascript"> var socket = io.connect('http://SERVER_IP:8080/'); socket.on('connect', function() { console.log("Connected"); window.addEventListener('devicemotion', ondevicemotion, false); }); // Receive a message socket.on('message', function(data) { console.log("Got: " + data); x = x + data.x; y = y + data.y; if (x > 600) { x = 599; } if (x < 0) { x = 0; } if (y > 400) { y = 399; } if (y < 0) { y = 1; } }); var x = 0; var y = 0; function setup() { createCanvas(600, 400); } function draw() { ellipse(x,y,80,80); } </script> </head> <body> </body> </html>