permalink

14

Introducción a Socket.io #nodejs

Para seguir esta introducción necesitas tener Node.js y Express.js

socket.io

Antes de nada describamos socket.io

Socket.io es una librería que nos permite manejar eventos en tiempo real mediante una conexión TCP y todo ello en JavaScript. Es realmente potente y podemos hacer todo tipo de aplicaciones en tiempo real. Hay muchos ejemplos de chat (que puede ser lo más llamativo) por ahí. Pero yo quiero hacer algo mucho más sencillo, para que comprender su funcionamiento lleve el menor tiempo posible.

  • Añadiendo socket.io al proyecto:

Si tenemos instalado Express.js ejecutamos el comando express socketexample y nos creará un directorio con un proyecto básico que podemos ejecutar entrando en el directorio cd socketexample y ejecutándolo node app.js

Ya tenemos nuestro proyecto express, ahora vamos a instalar Socket.io con npm install socket.io.

Antes de importarlo en nuestro proyecto necesitamos ajustar un poco el archivo app.js que nos ha creado express para hacer que socket.io escuche en el mismo puerto que lo hace express, para eso guardamos el servidor así:

var server = http.createServer(app).listen(app.get('port'), function(){ console.log("Express server listening on port " + app.get('port')); });

Y ahora sí importamos socket.io y lo iniciamos con `var io = require(‘socket.io’).listen(server);“

Debe quedar así:

/**
 * Module dependencies.
 */

var express = require('express')
  , routes = require('./routes')
  , http = require('http');

var app = express();

app.configure(function(){
  app.set('port', process.env.PORT || 3000);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
  app.use(express.errorHandler());
});

app.get('/', routes.index);

var server = http.createServer(app).listen(app.get('port'), function(){
  console.log("Express server listening on port " + app.get('port'));
});

var io = require('socket.io').listen(server);

Ya sí que tenemos el proyecto preparado para usar socket.io por parte del servidor.

  • Usando socket.io en el servidor y cliente.

Ya tenemos socket.io en el proyecto, vamos a usarlo en el servidor y en el cliente.

Para usar socket.io en el servidor debemos usar el objeto io. Socket.io se basa en eventos, pero para manejar estos eventos primero debemos crear una conexión entre el servidor y el cliente con el siguiente código: io.sockets.on('connection', callback(socket));

Este socket maneja la conexión cliente-servidor y nos ofrece las dos propiedades con las que vamos a trabajar, on (escucha eventos) y emit (emite eventos), aunque haya más como broadcast, set, of, volatile para temas más concretos.

Empecemos:

io.sockets.on('connection', function(socket){
  socket.emit('connected'); 
  //Evento creado por nosotros se puede llamar 'pepito'
});

Con socket.emit('connected'); emitimos un evento creado por nosotros, lo he llamado así porque creo que es el mejor nombre para decirle al cliente que estamos conectados.

Por ahora es suficiente para mostrar el mensaje de conectado.

Ahora, vamos a ver qué ponemos en el cliente, vamos a editar el archivo layout.jade para importar la librería socket.io que automáticamente sirve nuestro servidor en la ruta/socket.io/socket.io.js para ello la importamos en el head. Recordad que estamos usando Jade y debe hacerse así script(src='/socket.io/socket.io.js')

Después vamos a usarla al final de la vista index.jade, puesto que vamos a tratar con ella.

Nuestro propósito es que aparezca un mensaje que indique que estás conectado y después, que en tiempo real, pulsando un botón emita otro evento y el servidor indique el número de eventos que se ha recibido.

Primero vamos a hacer la lógica de conexión y desconexión, para ello he creado los dos mensajes, ocultando el de conectado y mostrando por defecto el de desconectado.

Veamos como va por ahora el código en el cliente:

extends layout

block content
  h1= title
  #disconected
    p Desconectado!
  #connected.hide
    p Conectado!
  input(type='button', value='Enviar pulsación')

  script
    //#1 Declaramos el objeto socket que se conectará en este caso a localhost
    var socket = io.connect('http://localhost');

    //#2 Función que muestra un mensaje u otro, dependiendo de la conexión.
    function toggle(){
      $("#disconected").toggleClass("hide");
      $("#connected").toggleClass("hide");
    }

    //#3 Si estamos conectados, muestra el log y cambia el mensaje
    socket.on('connected', function () {
      console.log('Conectado!');
      toggle();
    });

    //#4 Si nos desconectamos, muestra el log y cambia el mensaje.
    socket.on('disconnect', function () {
      console.log('Desconectado!');
      toggle();
      });
body {
  padding: 50px;
  font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}

a {
  color: #00B7FF;
}

#disconected p {
	color: red;
	background-color: rgba(200, 0, 0, 0.4);

}

#connected p {
	color: green;
	background-color: rgba(0,200,0,0.4);
}

.hide {
	display: none;
}
  • #1

Una vez hemos declarado el objeto socket, con el podemos recibir eventos consocket.on('evento', callback); y emitirlos con socket.emit('evento', data);

  • #2

Una simple función que usa jquery para mostrar u ocultar el mensaje de conectado o desconectado.

  • 3#

Escuchamos continuamente hasta que recibamos el evento creado por nosotros en el servidorserver.js y una vez recibido en el callback llamamos a la función creada en el punto 2 para cambiar el mensaje.

  • 4#

Permanece escuchando hasta que se desconecte, una vez desconectado volvemos a cambiar el mensaje indicando que estamos desconectados.

Si ejecutas el proyecto ahora y accedes a localhost:3000, verás que el mensaje aparece en verde. Corta el servidor con Ctrl+C y verás que el mensaje ha cambiado a desconectado. Vuelve a encenderlo sin recargar la página y comprueba que vuelve a verde.

  • Emitiendo eventos desde el cliente al servidor y contestar con datos

Ahora vamos a poner el botón que emitirá el evento, he utilizado un simpleimput(type='button', value='Enviar click')#click con la id click para capturar con jquery cuando se pulsa el elemento con esa id.

Al pulsarlo llamamos a socket.emit('click'); con jQuery y el servidor nos responderá con el evento otherClick.

Mejor veamos el código del cliente y del servidor.

/**
 * Module dependencies.
 */

var express = require('express')
  , routes = require('./routes')
  , http = require('http');

var app = express();

app.configure(function(){
  app.set('port', process.env.PORT || 3000);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
  app.use(express.errorHandler());
});

//Declaramos una variable con el número de clicks.
var clicks = 0;

app.get('/', routes.index);

//Asignamos a server la creación del servidor http.
var server = http.createServer(app).listen(app.get('port'), function(){
  console.log("Express server listening on port " + app.get('port'));
});

//Importamos socket.io utilizando el servidor creado anteriormente.
var io = require('socket.io').listen(server);

//Iniciamos la conexión.
io.sockets.on('connection', function(socket){
  //Emitimos nuestro evento connected
  socket.emit('connected');

  //Permanecemos a la escucha del evento click
  socket.on('click', function(){
    //Sumamos el click
    clicks++;

    //Emitimos el evento que dirá al cliente que hemos recibido el click
    //y el número de clicks que llevamos
    socket.emit('otherClick', clicks);
  });
});
extends layout

block content
  h1= title
  #disconected
    p Desconectado!
  #connected.hide
    p Conectado!
  h2 Has pulsado 0 veces!
  input(type='button', value='Enviar pulsación')#button

  script
    //#1 Declaramos el objeto socket que se conectará en este caso a localhost
    var socket = io.connect('http://localhost');

    //#2 Función que muestra un mensaje u otro, dependiendo de la conexión.
    function toggle(){
      $("#disconected").toggleClass("hide");
      $("#connected").toggleClass("hide");
    }

    //#3 Si estamos conectados, muestra el log y cambia el mensaje
    socket.on('connected', function () {
      console.log('Conectado!');
      toggle();
    });

    //#4 Si pulsas el botón, envía el evento click
    $('#button').click(function(){
      socket.emit('click');
      });

    //#5 El servidor nos responde al click con este evento y nos da el número de clicks en el callback.
    socket.on('otherClick', function(clicks){
      console.log('Clicks: '+clicks);
      $('h2').replaceWith('<h2>Has pulsado '+clicks+' veces!');
      });

    //#6 Si nos desconectamos, muestra el log y cambia el mensaje.
    socket.on('disconnect', function () {
      console.log('Desconectado!');
      toggle();
      });

En el servidor escuchamos el evento click, en el callback del evento sumamos un click a la variable y emitimos que hemos recibido un click y mandamos junto al evento el número de clicks.

En el cliente recibimos el evento otherClick y el número de clicks en el callback y los mostramos haciendo uso de jQuery.

Ejecutamos el servidor y vemos el funcionamiento.

  • Por último…

Si quieres, puedes poner un log en el callback del evento click en el server y comprobar que al pulsar el botón en el server se imprime.

Dejo el código en Github del proyecto completo y os animo a que añadáis mejoras para aprender a usar Socket.io con la práctica.

Autor de éste Artículo

Francisco López (@donflopez), webapp developer. Especializado en Node.js, Express.js, MongoDB y Socket.io. Localizable en Github,Twitter o en el blog donde actualmente escribe Tumblr.

  • hj

    Buen ejemplo, pero tengo un problema porque el evento otherClick me devuelve un valor undefined, a que se debe esto?

    • donflopez

      Muchas gracias! El código está actualizado en github, tal vez eso resuelva tu problema.

  • anonimo

    es muy bueno tu post y obviamente sabes mucho sobre el tema , pero creo que si lo detallaras mas seria mas facil para usuarios como yo que nos estamos muy a la orden del dia

    • donflopez

      Siento que no esté más detallado… creí haberlo hecho de la forma más sencilla posible. Lo tendré en cuenta en un futuro.

      Gracias!

  • nvls

    ummm estas utilizando jquery tamb…ya viene integrado a node.js o hay q agregarlo?

    • donflopez

      En el lado del cliente se añade de la forma tradicional.

  • richard

    muy buen ejemplo, seria mucho pedir ejemplos de socket.io el uso de rooms

    • donflopez

      Tomo nota.

      Gracias!!

  • Mauricio Caroca

    He seguido el tutorial y está muy bueno, pero tengo una duda, quiero el cliente en un .jade distinto a index por ejemplo, emitir los clicks en el index, pero en un client.jade verlos, que debo cambiar para que los eventos sean emitidos por el servidor y captador por el cliente?

  • Carlos

    Hola donflopez, te escribo para comunicarte que en el código de github el jade tienes errores.

  • Jairo Sánchez

    Con el package.json instalé los módulos (>npm install). En el archivo index.jade le agregué . (punto) despues de script y le cambié el doctype 5 por doctype html, primera línea en el archivo layout.jade. Funciona todo ok.

  • Jairo Sánchez

    ahhhh….gracias.

  • jorge luiz uribe

    hi

  • John

    1. El archivo socket.io/socket.io.js es un archivo que lo reconoce automaticamente el servirdor o como funciono esta ruta?

    2. Si importamos de nuestros modulos de node esta ruta , deberia servir de igual manera.

    Gracias por sus respuestas.

    Saludos,