Long Polling vs WebSocket en Go: La batalla por el tiempo real

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: El dilema del desarrollador

\n\n

Imagina: estás escribiendo un chat, un terminal bursátil o un juego en línea en Go. El cliente necesita recibir actualizaciones al instante. El viejo y confiable AJAX con sondeo periódico (polling) queda descartado: demasiadas solicitudes inútiles que agotan tanto el servidor como la batería del usuario. Quedan dos candidatos: Long Polling (sondeo largo) y WebSocket.

\n\n

Ambos resuelven el problema del "tiempo real", pero lo hacen de maneras fundamentalmente diferentes. ¿Cuál elegir para tu aplicación Go? Vamos a analizarlo sin rodeos, con ejemplos de código reales y un análisis honesto de pros y contras. Este artículo es tu guía en el mundo de las comunicaciones en tiempo real con Go.

\n\n

¿Qué es Long Polling en Go?

\n\n

Long Polling es una evolución del polling normal. El cliente envía una solicitud HTTP al servidor, pero el servidor no responde inmediatamente si no hay datos. "Se cuelga" (mantiene la conexión abierta) y espera hasta que ocurra un nuevo evento. Tan pronto como ocurre el evento, el servidor envía la respuesta y el cliente crea inmediatamente una nueva solicitud de Long Polling. El ciclo se repite.

\n\n

En Go, esto se implementa de manera muy elegante gracias a las gorutinas y los canales. El servidor puede "poner a dormir" el manejador de la solicitud hasta que aparezcan los datos.

\n\n

Ejemplo de servidor Long Polling en Go

\n\n
package main\n\nimport (\n    "fmt"\n    "net/http"\n    "time"\n)\n\n// Canal por el que llegan nuevos mensajes\nvar messages = make(chan string, 10)\n\nfunc longPollHandler(w http.ResponseWriter, r *http.Request) {\n    select {\n    case msg := <-messages:\n        fmt.Fprintf(w, "Nuevo mensaje: %s", msg)\n    case <-time.After(30 * time.Second):\n        // Timeout — si no hay mensajes en 30 segundos\n        http.Error(w, "Timeout", http.StatusGatewayTimeout)\n    }\n}\n\nfunc main() {\n    // Gorutina que simula la llegada de nuevos mensajes\n    go func() {\n        for {\n            time.Sleep(5 * time.Second)\n            messages <- fmt.Sprintf("Hora: %s", time.Now().String())\n        }\n    }()\n\n    http.HandleFunc("/poll", longPollHandler)\n    http.ListenAndServe(":8080", nil)\n}\n
\n\n

El cliente en JavaScript se vería así: después de recibir la respuesta (o un timeout), llama inmediatamente a /poll de nuevo. Simple, confiable, funciona a través de cualquier proxy y firewall.

\n\n

WebSocket en Go: Dúplex completo

\n\n

WebSocket es un protocolo que, después del handshake (HTTP Upgrade), convierte la conexión en un canal bidireccional permanente. El servidor puede enviar datos al cliente en cualquier momento, y el cliente al servidor. Sin solicitudes repetidas, sin timeouts.

\n\n

En Go, la biblioteca estándar no tiene soporte integrado para WebSocket, pero existe el estándar de oro: el paquete gorilla/websocket. Es estable, bien documentado y utilizado en producción por miles de proyectos.

\n\n

Ejemplo de servidor WebSocket en Go

\n\n
package main\n\nimport (\n    "log"\n    "net/http"\n    "time"\n\n    "github.com/gorilla/websocket"\n)\n\nvar upgrader = websocket.Upgrader{\n    CheckOrigin: func(r *http.Request) bool {\n        return true // Para desarrollo. ¡En producción, verificar!\n    },\n}\n\nfunc wsHandler(w http.ResponseWriter, r *http.Request) {\n    conn, err := upgrader.Upgrade(w, r, nil)\n    if err != nil {\n        log.Print("Error al actualizar:", err)\n        return\n    }\n    defer conn.Close()\n\n    // Bucle infinito de lectura y escritura\n    for {\n        // Leer mensaje del cliente\n        _, message, err := conn.ReadMessage()\n        if err != nil {\n            log.Println("Error de lectura:", err)\n            break\n        }\n        log.Printf("Recibido: %s", message)\n\n        // Enviar respuesta (o notificación push)\n        err = conn.WriteMessage(websocket.TextMessage, []byte("Servidor: "+time.Now().String()))\n        if err != nil {\n            log.Println("Error de escritura:", err)\n            break\n        }\n    }\n}\n\nfunc main() {\n    http.HandleFunc("/ws", wsHandler)\n    log.Pr                

Blogs

Book Recommendations