Haciendo Whatsapp (I): Eligiendo Protocolo

Este mes he revisado las empresas a las que he ayudado a implementar sistemas de chat basados en ejabberd o MongooseIM, son ya 9 las empresas que han confiado en mi para ayudarles en España, Francia, UK, Luxemburgo, Finlandia y Estados Unidos. Todos intentan copiar los pasos de WhatsApp, ¿cómo montan sus sistemas?

En una serie de artículos me gustaría ir comentando cómo se construye un sistema como Whatsapp, los beneficios, las desventajas y cada una de las elecciones a las que se tiene que ir enfrentando cada empresa. En este primer artículo vamos a comenzar por el protocolo.

¿Cómo nos comunicamos?

Es de sobra conocido que WhatsApp usa XMPP como protocolo de comunicaciones. Pero no es el único que comenzó utilizando este protocolo y no es el único protocolo utilizado. Como decía en otro artículo, también hay otros que han decidido implementar su propio protocolo como MTProto usado en Telegram o implementar otro protocolo más afín a redes móviles como es MQTT (en este caso implementado por el chat de Facebook).

Muchos intentan implementar sus sistemas de chat sobre HTTP sin mucho éxito. La falta de éxito no se debe a emplear una plataforma concreta, sino a la carencia de buenas prácticas que se recogen en otros protocolos como XMPP.

MQTT o MTProtocol

MTProto se basa en MQTT por tanto podemos hablar de ambos al mismo tiempo. En principio podemos considerar a MQTT como una simplificación o la base de MTProtocol. En realidad MQTT es un protocolo para gestión de mensajes de cola y podemos verlo presente en sistemas como RabbitMQ o VerneMQ.

El problema de MQTT es la carencia de un protocolo específico para notificar acciones específicas. En MQTT podemos enviar cualquier tipo de mensaje por lo que está en nuestra mano definir el protocolo que indique cuándo alguien escribe, cómo almacenar los mensajes para un usuario e incluso cómo trabajar con mensajes de grupos.

Por otro lado, MTProtocol ya tiene las tareas hechas en este sentido. Está pensado a nivel de protocolo para indicar el estado de los usuarios (si están en línea o no, y si no desde cuándo), enviar mensajes individuales, de grupo, imágenes, etc.

La pega de MTProtocol es la carencia de servidores que lo implementen. De momento solo están disponibles los propios servidores de Telegram, por lo que si se quiere desarrollar un sistema propio mantendrás una dependencia fuerte con sus servidores.

¿Por qué no HTTP?

Los servidores web han sido diseñados para atender una petición y morir. Entre peticiones no se guarda información y aún manteniendo la conexión abierta en modo keep-alive (HTTP/1.1) cada petición sigue siendo individual.

Además, aunque HTTP/2.0 dispondrá de capacidades para comunicar al servidor con el cliente sin necesidad de que el cliente inicie antes una petición (algo parecido a lo que se hace ahora con SPDY), las peticiones siguen necesitando las cabeceras de autenticación o el token que indique la sesión del usuario.

A través de websocket sí es posible mantener la comunicación y de hecho, los navegadores que utilizan XMPP directamente a través de BOSH se están viendo beneficiados ahora por la posibilidad de emplear websockets en lugar de HTTP para la comunicación XMPP ganando velocidad. No obstante, cabe destacar que un websocket no es HTTP y que hay lenguajes como PHP que no soportan websockets u otros sistemas como Ruby on Rails que no los soportan bien del todo.

Finalmente nos damos cuenta de que es mejor emplear otro protocolo diferente para poder tener los beneficios de la comunicación en tiempo real e información de los usuarios sin necesidad de tener que hacer polling al servidor cada poco tiempo.

¿Por qué XMPP?

La respuesta dada por la mayoría es: porque lo usa Whatsapp y a ellos le va bien. Pero no sería una respuesta acertada, sobretodo teniendo en cuenta que Whatsapp modificó de base el protocolo XMPP agregando cambios como FunXMPP y otros a nivel de comunicación para hacerlo más fiable y rápido.

La respuesta correcta sería: porque tiene las tareas hechas.

Sí. Es un protocolo basado en XML que permite ampliaciones. El protocolo está definido en el RFC–6120 pero tiene su propio sitio de especificaciones XEP (XMPP Extension Protocol).

La base del protocolo en el RFC cubre la presencia de los usuarios, la lista de contactos (roster), el envío de mensajes individuales y sobretodo la especificación de cómo utilizar el XML, autenticación y TLS. El resto del protocolo se puede encontrar en los XEP, como por ejemplo:

También podemos encontrar XEPs que están en estado experimental (pero implementados en algunos servidores de XMPP) como son:

  • XEP–0369: MIX (Mediated Information eXchange) como mejora de groupchat.
  • XEP-xxxx: MUC-Light, una versión adaptada para dispositivos móviles y mucho más ligera de MUC. Aún no aceptada y por lo que no tiene número.

Incluso cada día 1 de abril podemos ver publicaciones en broma de XEPs:

Ventajas de XMPP

Como se ha mencionado antes, el motivo de elegir XMPP es tener las tareas hechas. El protocolo nació en 1999, ha sido empleado extensamente en sistemas de chat por todo el mundo, primero con aplicaciones cliente de escritorio y más tarde por aplicaciones móviles como Whatsapp.

Podemos citar las ventajas en algunos puntos:

  • Sistema de autenticación y cifrado integrado: disponemos de un sistema de autenticación incluído en el sistema, no obstante también podemos usar el modo anónimo. El sistema puede cifrarse a través de TLS tras la conexión. Se ve puede ver más en el RFC–7590.

  • Presencia: las conexiones son TCP persistentes. Cada vez que un usuario se conecta el servidor envía un mensaje de presencia a todos los usuarios que tengan suscrita su presencia en la lista de contactos (roster) y al cerrar la sesión también se recibe la presencia no disponible (u offline).

  • Lista de contactos: dispone por defecto de una lista de contactos muy flexible que permite gestionar la solicitud de amistad de varias formas diferentes.

  • Sistema de Perfil: también disponemos de un perfil ya construido en el sistema a través del XEP–0054 para configurar los datos del usuario e incluso realizar búsquedas a traves del XEP–0055.

  • Sistema de mensajes fuera de línea: cuando un usuario no está, todos sus mensajes son almacenados para ser enviados al usuario en el momento que vuelva a estar en línea.

  • Sistema de chat en grupo: normalmente a través del XEP–0045, pero como hemos visto anteriormente, se pueden emplear otras extensiones más ligeras.

  • Sistema de bloqueo: a través del XEP–0191 disponemos de la posibilidad de bloquear contactos para evitar que envíen información o mensajes a otros usuarios.

  • Llamadas de VoIP: a través del XEP–0166, también conocido como Jingle, podemos realizar llamadas entre los usuarios.

  • Personalización: en puntos anteriores hemos visto que muchas características no se encuentran en el lenguaje sino en extensiones del mismo. Esto es en sí una ventaja porque permite crear extensiones personalizadas para todo lo que necesitemos hacer.

Como se puede ver, en un solo protocolo tenemos todo lo necesario para el intercambio de información entre usuarios. Pero…

Desventajas

Algo malo tenía que haber. Usuarios y desarrolladores de otros protocolo seañalan como desventaja el uso de XML en lugar de binario para hacer el lenguaje más compacto y no tener que emplear simplificaciones como FunXMPP. Sin embargo el uso de XML es en sí la ventaja que le hace poder ser extensible fácilmente.

Otra desventaja derivada del uso de XML es la imposibilidad de enviar vídeos o imágenes a través del protocolo. Si revisamos las extensiones de Avatar o vCard veremos que se pueden enviar imágenes pero en formato base64, por lo que ocupan mucho más espacio. Esto se ha intentado corregir aportando una comunicación Jingle para el envío de multimedia, tal y como se especifica en el XEP–0234 (Jingle File Transfer).

La última desventaja está relacionada con el transporte en sí. Teniendo en cuenta que XMPP es un protocolo asíncrono y está basado en una conexión persistente TCP, en equipos de sobremesa, no existe mucho problema porque las conexiones suelen ser fiables (más o menos), pero en redes móviles y WiFi, la conectividad se puede perder en cualquier momento. E incluso si se configura el dispositivo móvil en modo avión, se cierra la pila TCP completamente sin cerrar de forma correcta las conexiones.

El servidor no se da cuenta en ningún momento que una conexión ha desaparecido cuando se cierra mal. Habría que emplear sistemas de keep-alive en TCP y aún así tardaría el tiempo de timeout en darse cuenta de que el usuario ya no está conectado. En ese entretanto, todos los mensajes enviados a ese usuario se pierden.

Por lo tanto, la gran desventaja de XMPP es que si la conexión TCP se pierde, los mensajes se pierden también. No obstante, se han intentado realizar sistemas de control de mensajes para minimizar esto, como por ejemplo el control del flujo de datos en el XEP–0198, o el uso de acuses de recibo XEP–0184.

Sin embargo con un buen control e implementación del protocolo podemos evitar todas estas deventajas y aprovechar todas sus ventajas. Que no son pocas.

Servidores

Tal y como hizo Whatsapp, podemos elegir un servidor ya implementado. Hay empresas que han comenzado con OpenFire. Si tienes previsto tener más de 50 usuarios conectados en línea, con servidores en un proveedor económico y sin quebrarte la cabeza con soluciones de clusterización en Java, te recomiendo que uses ejabberd o MongooseIM. También existe la posibilidad de emplear Prosody, un servidor muy completo escrito en Python pero sin capacidad de trabajo en cluster, por lo que limitado al número total de conexiones simultáneas de usuarios.

Como puntos positivos para ejabberd comentar que ProcessOne lo ha convertido en su producto estrella e implementan nuevas características cada pocos meses. Es muy estable y tiene la capacidad de incrustar código de terceros en forma de módulos sin necesidad de tocar el código fuente original. Además, en las últimas versiones han hecho énfasis en incluir otros lenguajes para el desarrollo de extensiones como Lua o Elixir.

Si quieres elegir MongooseIM, solo indicar que este es un fork de ejabberd 2.18 reescrito para incluir las mejores prácticas de Erlang/OTP. No en vano fue reescrito por Erlang Solutions. Algunas características de ejabberd fueron eliminadas (como la interfaz web de administración o el sistema de PubSub, XEP–0060) y agregaron otras características como Archiving, XEP–0313, MUC-Light así como todo su sistema construido con rebar y usando dependencias.

A lo largo de las siguientes entregas me basaré más en ejabberd por el motivo de que lo veo más estable últimamente que MongooseIM.

Conclusiones

Hasta aquí llegamos de momento. Hemos repasado la base de XMPP y te recomiendo si estás interesado en seguir aprendiendo e implementar tu sistema de XMPP, que adquieras el libro de XMPP que comento en este artículo.

Para saber más sobre lo que esperas y orientar mejor los artículos así como poder ofrecerte una mejor ayuda en caso de que la necesites, puedes rellenar la siguiente encuesta.

¿Te ha servido la información? ¿te interesa crear un sistema de chat para una aplicación móvil o web? ¿crees que podríamos mejorar aún más la información expuesta? ¡Déjamos un comentario!