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.
Java and Android have basic support for regular socket communication. While this is fantastic, it is a bit lower level than I would like to delve into and less useful for us in the short term.
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 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.
Sam Slover put together a great getting started with Amazon guide: http://itp.nyu.edu/~sve204/alwaysonalwaysconnected_spring14/amazon-node-server-setup.txt
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: https://github.com/LearnBoost/socket.io/wiki/Exposed-events
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, that works great on the web but how about an Android app that can connect to the same server and interact with the web page.
This library provides the Socket.io interface to Android applications. https://github.com/Gottox/socket.io-java-client
To use it, you have to clone and build it. The readme is a good place to start.
This blog post is also a worthwhile read: http://nkzawa.tumblr.com/post/46850605422/connecting-to-a-socket-io-server-from-android
try { SocketIO socket = new SocketIO("http://54.221.90.69:8080"); socket.connect(new IOCallback() { @Override public void on(String event, IOAcknowledge ack, Object... args) { if (event.equals("otherevent")) { Log.d("SocketIO", "otherevent " + args[0]); } } @Override public void onMessage(JSONObject json, IOAcknowledge ack) { Log.v("SocketIO", json.toString()); } @Override public void onMessage(String data, IOAcknowledge ack) { Log.v("SocketIO", data); } @Override public void onError(SocketIOException socketIOException) { socketIOException.printStackTrace(); } @Override public void onDisconnect() { Log.v("SocketIO", "Disconnected"); } @Override public void onConnect() { Log.v("SocketIO", "Connected"); } }); socket.emit("message", "android says hello"); } catch (Exception e) { e.printStackTrace(); }
As with BlueTooth and other threaded operations, in order for those threads to work with the UI thread and affect the user interface or display anything to the user, we need to use a handler to pass the data from the data thread to the UI thread.
The following snippet assumes a TextView in the Layout with the id textView1.
TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) this.findViewById(R.id.textView1); try { SocketIO socket = new SocketIO("http://54.221.90.69:8080"); socket.connect(new IOCallback() { @Override public void on(String event, IOAcknowledge ack, Object... args) { if (event.equals("otherevent")) { Log.v("SocketIO", "otherevent " + args[0]); } else { Log.v("SocketIO", event + " " + args[0]); } } @Override public void onMessage(JSONObject json, IOAcknowledge ack) { Log.v("SocketIO", json.toString()); handleMessage(json.toString()); } @Override public void onMessage(String data, IOAcknowledge ack) { Log.v("SocketIO", data); handleMessage(data); } @Override public void onError(SocketIOException socketIOException) { socketIOException.printStackTrace(); } @Override public void onDisconnect() { Log.v("SocketIO", "Disconnected"); } @Override public void onConnect() { Log.v("SocketIO", "Connected"); } }); socket.emit("message", "android says hello"); } catch (Exception e) { e.printStackTrace(); } } // Handlers let us interact with threads on the UI thread // The handleMessage method receives messages from other threads and will act upon it on the UI thread Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // Pull out the data that was packed into the message with the key "message" String messageData = msg.getData().getString("message"); // Send it over to the view tv.setText(messageData); } }; public void handleMessage(String message) { // First we obtain a message object Message msg = handler.obtainMessage(); // Create a bundle to hold data Bundle bundle = new Bundle(); // Put our value with the key "message" bundle.putString("message", message); // Set the message data to our bundle msg.setData(bundle); // and finally send the message via the handler handler.sendMessage(msg); }
Full example: https://github.com/vanevery/AndroidSocketIOTest