Los WebSockets son una característica importante de HTML5. Esto implementa sockets basados en navegadores, lo que permite a los navegadores tener comunicación en dos vías con los servidores. La mayoría de navegadores populares como Firefox, Chrome y Safari proveen soporte para WebSockets.
Las personas utilizan "roll polling" para los servicios de mensajes instantaneos antes que los WebSockets nacieran, lo que permitía alos clientes enviar peticiones HTTP periódicamente. El servidor entonces retornaba la información mas reciente a los clientes. La desventaja de este método es que requiere que los clientes mantengan enviando muchas conexiones al servidor, lo que consume mucho ancho de banda.
Los WebSockets una un tipo especial de encabezado que reduce el número de apretones de manos requeridos entre el servidor y el cliente, a solo uno, para establecer la conexión. Esta conexión permanecerá activa por todo su tiempo de vida, y puedes usar JavaScript para enviar o recibir información de esta conexión, como en el caso de un socket TCP convencional. Esto resuelve muchos de los dolores de cabeza de las aplicaciones web en tiempo real y le trae las siguientes ventajas al protocolo HTTP:
- Solo una conexión TCP para un solo cliente web.
- Los servidores de WebSockets pueden enviar información a los clientes.
- Los encabezados mas livianos reducen la carga de transmisión de red.
Las URLs de los WebSockets comienzan con un ws:// o un wss://. La siguiente figura muestra el proceso de comunicación de un websocket. Un encabezado particular es enviado al servidor como parte del apretón de manos y la conexión es establecida. Entonces, servidores y cliente son capaces de recibir y enviar información a través del WebSocket
Figura 8.2 Principio de los websockets
El protocolo de websockets es muy fácil. Después de completar el apretón de manos inicial, una conexión es establecida. La comunicación subsecuenta comenzará con un "\x00" y terminará con un "\xFF". Este prefijo y sufijo será visible a los clientes, porque el websocket romperá los datos entre ambos finales, produciendo los datos puros.
Las conexiones por websockets son pedidas por los navegadores y respondidas por los servidores. Después la conexión es establecida. Este proceso se llama "apretón de manos".
Considera las siguientes peticiones y respuestas
Figura 8.3 Peticiones y respuestas de un websocket
"Sec-WebSocket-key" es generada aleatoreamente, como puedes haberlo adivinado, y es codificada a base 64. Los servidores encesitan concatenar esta llave a una cadena después de aceptar una petición:
258EAFA5-E914-47DA-95CA-C5AB0DC85B11
Supón que tenemos f7cb4ezEAl6C3wRaU6JORA==
, Entonces enviamos:
f7cb4ezEAl6C3wRaU6JORA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
Usa sha1 para computar el valor binario y luego base 64 para codificarlo. Entonces tendremos:
rE91AJhfC+6JdVcVXOGJEADEJdQ=
Usa esto como valor en el encabezado de respuesta Sec-WebSocket-Accept
.
La librería estándar de Go no provee soporte para WebSockets. Sin embargo el paquete websocket
que es un subpaquete de go.net
lo es, y es oficialmente mantenido mantenido y soportado.
Usa go get
para instalar este paquete:
go get golang.org/x/net/websocket
Los WebSockets tienen lados de cliente y servidor. Veamos un ejemplo simple de un usuario ingresa alguna información en el lado del cliente y la envía al lado del servidor a través de un WebSocket, seguido por el servidor reenviando la información al cliente.
Lado del cliente:
<html>
<head></head>
<body>
<script type="text/javascript">
var sock = null;
var wsuri = "ws://127.0.0.1:1234";
window.onload = function() {
console.log("onload");
sock = new WebSocket(wsuri);
sock.onopen = function() {
console.log("connected to " + wsuri);
}
sock.onclose = function(e) {
console.log("connection closed (" + e.code + ")");
}
sock.onmessage = function(e) {
console.log("message received: " + e.data);
}
};
function send() {
var msg = document.getElementById('message').value;
sock.send(msg);
};
</script>
<h1>WebSocket Echo Test</h1>
<form>
<p>
Message: <input id="message" type="text" value="Hello, world!">
</p>
</form>
<button onclick="send();">Send Message</button>
</body>
</html>
Como puedes ver, es muy facil utilizar las funciones Javascript del lado del cliente para establecer la conección. El evento onopen
es activado después de terminar exitosamente el proceso del apretón de manos. Esto le dice al cliente que la conexión ha sido creada exitosamente. El cliente trata de abrir una conexions usualmente ata estos cuatro eventos:
- 1)onopen: activado cuando la conexión es establecida.
- 2)onmessage: activado después de recibir un mensaje.
- 3)onerror: activado cuando un error ha ocurrido.
- 4)onclose: activuado cuando la conexión ha sido cerrada.
Código del servidor:
package main
import (
"golang.org/x/net/websocket"
"fmt"
"log"
"net/http"
)
func Echo(ws *websocket.Conn) {
var err error
for {
var reply string
if err = websocket.Message.Receive(ws, &reply); err != nil {
fmt.Println("Can't receive")
break
}
fmt.Println("Received back from client: " + reply)
msg := "Received: " + reply
fmt.Println("Sending to client: " + msg)
if err = websocket.Message.Send(ws, msg); err != nil {
fmt.Println("Can't send")
break
}
}
}
func main() {
http.Handle("/", websocket.Handler(Echo))
if err := http.ListenAndServe(":1234", nil); err != nil {
log.Fatal("ListenAndServe:", err)
}
}
Cuando un cliente envía la información, el cliente la recive (Receive
) y usa un Send
para enviar la respuesta.
Figura 8.4 Servidor WebSocket recibiendo información.
A través de el ejemplo de arriba, podemos ver que la implemenación de un cliente y servior WebSocket es muy conveniente. Podemos usar el paquete net
directamente en Go. Con el rápido desarrollo de HTML5, pienso que los WebSockets tendrán un rol mucho mas importante en las aplicaciones web modernas; deberíamos ser capaces al menos de estar familiarizados con ellos.