Event-System¶
Socket.IO basiert auf einem bidirektionalen Event-System. Dieses Dokument erklärt alle verfügbaren Events und deren Verwendung.
Inhaltsverzeichnis¶
Lifecycle-Events¶
Diese Events werden automatisch während des Verbindungslebenszyklus emittiert.
OnConnect¶
Wird ausgeführt, wenn die Verbindung erfolgreich hergestellt wurde.
client.OnConnect(func() {
fmt.Println("Conectado al servidor")
// Aquí puedes emitir eventos iniciales
client.Emit("join-room", "sala-123")
})
OnDisconnect¶
Wird ausgeführt, wenn die Verbindung geschlossen wird. Erhält den Grund für die Trennung.
client.OnDisconnect(func(reason string) {
fmt.Printf("Desconectado: %s\n", reason)
// Razones comunes:
// - "io server disconnect" - El servidor cerró la conexión
// - "io client disconnect" - El cliente cerró la conexión
// - "ping timeout" - El servidor no respondió al ping
// - "transport close" - El transporte subyacente se cerró
// - "transport error" - Error en el transporte
})
OnError¶
Wird ausgeführt, wenn ein Verbindungsfehler auftritt.
client.OnError(func(err error) {
fmt.Printf("Error de conexión: %v\n", err)
// Puedes implementar lógica de recuperación aquí
if err.Error() == "authentication failed" {
fmt.Println("Verifica tus credenciales")
}
})
Reconnection-Events¶
Diese Events ermöglichen die Überwachung und Steuerung des automatischen Reconnection-Prozesses.
OnReconnectAttempt¶
Wird vor jedem Reconnection-Versuch ausgeführt.
client.OnReconnectAttempt(func(attempt int) {
fmt.Printf("Intentando reconectar... (intento %d)\n", attempt)
})
OnReconnect¶
Wird ausgeführt, wenn die Reconnection erfolgreich ist.
client.OnReconnect(func(attempt int) {
fmt.Printf("Reconectado exitosamente después de %d intentos\n", attempt)
// Re-subscribirse a eventos o actualizar estado
client.Emit("resume-session", lastSessionId)
})
OnReconnectError¶
Wird ausgeführt, wenn ein Reconnection-Versuch fehlschlägt.
OnReconnectFailed¶
Wird ausgeführt, wenn alle Reconnection-Versuche fehlschlagen.
client.OnReconnectFailed(func() {
fmt.Println("Reconexión falló después de todos los intentos")
// Notificar al usuario o implementar fallback
notifyUser("No se pudo restablecer la conexión")
})
Vollständiges Reconnection-Beispiel¶
client := socketio.New("ws://localhost:3000", socketio.Options{
ReconnectAttempts: 5,
ReconnectDelay: time.Second,
ReconnectDelayMax: 5 * time.Second,
})
var reconnectCount int
client.OnReconnectAttempt(func(attempt int) {
reconnectCount = attempt
fmt.Printf("⏳ Intento %d de reconexión...\n", attempt)
})
client.OnReconnect(func(attempt int) {
fmt.Printf("✅ Reconectado después de %d intentos\n", attempt)
reconnectCount = 0
})
client.OnReconnectError(func(err error) {
fmt.Printf("❌ Error en intento %d: %v\n", reconnectCount, err)
})
client.OnReconnectFailed(func() {
fmt.Println("💥 Reconexión falló permanentemente")
})
Custom Events¶
Sie können beliebige vom Server emittierte Custom Events empfangen.
Events empfangen¶
client.On("message", func(data ...interface{}) {
fmt.Printf("Mensaje recibido: %v\n", data[0])
})
client.On("user-joined", func(data ...interface{}) {
username := data[0].(string)
fmt.Printf("%s se unió a la sala\n", username)
})
client.On("notification", func(data ...interface{}) {
notification := data[0].(map[string]interface{})
fmt.Printf("Notificación: %s\n", notification["message"])
})
Mehrere Argumente¶
Events können mehrere Argumente empfangen:
client.On("chat-message", func(data ...interface{}) {
username := data[0].(string)
message := data[1].(string)
timestamp := data[2].(float64)
fmt.Printf("[%s] %s: %s\n",
time.Unix(int64(timestamp), 0).Format("15:04"),
username,
message)
})
Namespaces¶
Events können in bestimmten Namespaces empfangen werden:
// Namespace por defecto
client.On("global-event", func(data ...interface{}) {
fmt.Println("Evento global:", data[0])
})
// Namespace personalizado
chat := client.Of("/chat")
chat.On("message", func(data ...interface{}) {
fmt.Println("Mensaje de chat:", data[0])
})
admin := client.Of("/admin")
admin.On("alert", func(data ...interface{}) {
fmt.Println("Alerta de admin:", data[0])
})
Event Handlers¶
Handler-Signatur¶
Event Handlers haben folgende Signatur:
Der Parameter data enthält alle mit dem Event gesendeten Argumente.
Type Assertions¶
Sie müssen Type Assertions durchführen, um die empfangenen Daten zu verwenden:
client.On("user-data", func(data ...interface{}) {
if len(data) == 0 {
return
}
// Type assertion a map
if userData, ok := data[0].(map[string]interface{}); ok {
name := userData["name"].(string)
age := userData["age"].(float64)
fmt.Printf("Usuario: %s, Edad: %.0f\n", name, age)
}
})
Fehlerbehandlung in Handlers¶
client.On("data", func(data ...interface{}) {
defer func() {
if r := recover(); r != nil {
fmt.Printf("Error en handler: %v\n", r)
}
}()
// Procesar datos
processData(data[0])
})
Acknowledgments¶
Acknowledgments ermöglichen bidirektionale Antworten.
Mit Acknowledgment senden¶
client.EmitWithAck("get-user", func(response ...interface{}) {
user := response[0].(map[string]interface{})
fmt.Printf("Usuario obtenido: %v\n", user)
}, "user-123")
Auf Acknowledgments antworten¶
client.On("save-data", func(data ...interface{}) {
// Último argumento es el callback de acknowledgment
if len(data) < 2 {
return
}
payload := data[0]
if ack, ok := data[len(data)-1].(func(...interface{})); ok {
// Procesar datos
success := saveToDatabase(payload)
// Responder al servidor
if success {
ack(map[string]interface{}{
"status": "ok",
"message": "Datos guardados exitosamente",
})
} else {
ack(map[string]interface{}{
"status": "error",
"message": "Error al guardar datos",
})
}
}
})
Acknowledgment-Timeout¶
Sie können ein globales Timeout für Acknowledgments konfigurieren:
client := socketio.New("ws://localhost:3000", socketio.Options{
AckTimeout: 5 * time.Second, // Timeout de 5 segundos
})
client.EmitWithAck("slow-operation", func(response ...interface{}) {
if response == nil {
fmt.Println("Timeout: el servidor no respondió a tiempo")
return
}
fmt.Println("Respuesta:", response[0])
}, "datos")
Binäre Events¶
Um binäre Daten zu senden (Bilder, Dateien, etc.):
// Leer archivo
imageData, err := os.ReadFile("photo.jpg")
if err != nil {
log.Fatal(err)
}
// Emitir evento binario
client.Of("/").EmitBinary("upload", imageData, map[string]interface{}{
"filename": "photo.jpg",
"size": len(imageData),
})
Binäre Daten empfangen¶
client.On("file", func(data ...interface{}) {
// Primer argumento es el buffer binario
if binaryData, ok := data[0].([]byte); ok {
fmt.Printf("Archivo recibido: %d bytes\n", len(binaryData))
// Guardar archivo
err := os.WriteFile("downloaded.dat", binaryData, 0644)
if err != nil {
fmt.Println("Error al guardar archivo:", err)
}
}
// Argumentos adicionales
if len(data) > 1 {
metadata := data[1].(map[string]interface{})
fmt.Printf("Metadata: %v\n", metadata)
}
})
Best Practices¶
1. Empfangene Daten validieren¶
Validieren Sie Daten immer vor der Verwendung:
client.On("update", func(data ...interface{}) {
if len(data) == 0 {
fmt.Println("Evento sin datos")
return
}
payload, ok := data[0].(map[string]interface{})
if !ok {
fmt.Println("Formato de datos inválido")
return
}
// Usar datos validados
processUpdate(payload)
})
2. Goroutines für lange Operationen verwenden¶
Blockieren Sie den Event Handler nicht mit langen Operationen:
client.On("process", func(data ...interface{}) {
go func() {
// Operación larga
result := heavyComputation(data[0])
// Emitir resultado
client.Emit("result", result)
}()
})
3. Ressourcen aufräumen¶
Deregistrieren Sie Handlers, wenn Sie sie nicht mehr benötigen:
// El cliente no proporciona Off() directamente
// En su lugar, usa flags o canales para controlar la ejecución
done := make(chan struct{})
client.On("temp-event", func(data ...interface{}) {
select {
case <-done:
return // Ignorar evento
default:
processEvent(data)
}
})
// Cuando termines
close(done)
4. Strukturiertes Logging¶
Implementieren Sie konsistentes Logging:
func logEvent(event string, data ...interface{}) {
fmt.Printf("[%s] Evento: %s, Datos: %v\n",
time.Now().Format("15:04:05"),
event,
data)
}
client.On("important-event", func(data ...interface{}) {
logEvent("important-event", data...)
processEvent(data)
})