2012-02-16 15 views
6

Estoy tratando de hacer que un simple reenviador de comandos conecte la computadora de mi casa a un servidor que poseo, de modo que pueda enviar comandos a mi servidor y mi pc doméstica lo obtenga. Esos comandos son simples pausas/reanudaciones para mi descargador. Mi diseño es que en un servidor ejecuto una instancia de concentrador, que crea una ventana para pasar comandos y una ventana para que back-end pase esos comandos a mi pc. Estoy limitando esas dos "ventanas" con un canal, ejecutan un servidor. Cuando un cliente se conecta y envía un mensaje al concentrador, se transmite por un canal a la ventana de back-end y luego al back-end real (en mi PC hogareña). Cuando back-end responde a la ventana de back-end en el hub, el hub imprime el resultado de vuelta al cliente.vaya websockets eof

Con este enfoque, solo el primer mensaje pasa y funciona con mi programa de descarga. Tengo que volver a conectar el backend de la pc de mi casa con el concentrador cada vez que recibo un mensaje para que funcione correctamente. No creo que sea la forma correcta de websockets, así que aquí estoy. Después de una solicitud exitosa (cuando el servidor finaliza su trabajo y responde el resultado), se bifurca para siempre con un error EOF.

Las partes importantes del código son:

Si coloca la fuente en su GOPATH (estoy desarrollando para la punta versión de go to support websockets moderna), para compilarlo: go build gosab/cmd, ejecutarlo:

  • ./cmd -mode="hub"centro
  • ./cmd -mode="backend" --address="localhost:8082"backend

para pasar mensajes al concentrador, utilice este javascript:

var s = new WebSocket("ws://localhost:8082") 
s.send("1 5") 

Entonces, ¿cómo lo manejo? ¿Los canales son una buena forma de comunicarse entre dos solicitudes diferentes?

+0

Reinventando la rueda, ¿tal vez por diversión? Suena muy parecido a Salt: http://saltstack.org/ o Puppet Labs Marionette: http://docs.puppetlabs.com/mcollective/index.html – djangofan

+0

buenos enlaces, pero quiero implementar algo como esto por mi cuenta – farnoy

+0

I use algo similar (un servidor de juegos con comunicación entre el navegador y el servidor en websockets) para saber cómo hacerlo de una vez, pero no entiendo cuál es la verdadera pregunta aquí.Si solo se trata de "son canales una buena forma de comunicarse", la respuesta es SÍ. –

Respuesta

7

Me sorprende que no hayas recibido una respuesta a esto.

Lo que debes hacer es algo como el siguiente código. Cuando recibe una conexión entrante de websocket, se genera una nueva goroutine para esa conexión. Si dejas que esa rutina termine, desconectará el cliente de websocket.

Supongo que no necesariamente va a ejecutar el cliente y el servidor en la misma computadora. Si siempre lo está, entonces sería mejor hacer la comunicación internamente a través de canales o tal en lugar de usar websockets o un puerto de red. Solo lo menciono porque no estoy completamente seguro de para qué lo estás usando. Solo espero haber respondido la parte correcta de tu pregunta.

package main 

import (
    "code.google.com/p/go.net/websocket" 
    "flag" 
    "fmt" 
    "net/http" 
    "os" 
    "time" 
) 

type Message struct { 
    RequestID  int 
    Command  string 
    SomeOtherThing string 
    Success  bool 
} 

var mode *string = flag.String("mode", "<nil>", "Mode: server or client") 
var address *string = flag.String("address", "localhost:8080", "Bind address:port") 

func main() { 
    flag.Parse() 

    switch *mode { 
    case "server": 
     RunServer() 
    case "client": 
     RunClient() 
    default: 
     flag.Usage() 
    } 
} 

func RunServer() { 
    http.Handle("/", http.FileServer(http.Dir("www"))) 
    http.Handle("/server", websocket.Handler(WSHandler)) 
    fmt.Println("Starting Server") 
    err := http.ListenAndServe(*address, nil) 
    if err != nil { 
     fmt.Printf("HTTP failed: %s\n", err.Error()) 
     os.Exit(1) 
    } 
} 

func WSHandler(ws *websocket.Conn) { 
    defer ws.Close() 
    fmt.Println("Client Connected") 
    for { 
     var message Message 
     err := websocket.JSON.Receive(ws, &message) 
     if err != nil { 
      fmt.Printf("Error: %s\n", err.Error()) 
      return 
     } 
     fmt.Println(message) 

     // do something useful here... 

     response := new(Message) 
     response.RequestID = message.RequestID 
     response.Success = true 
     response.SomeOtherThing = "The hot dog left the castle as requested." 
     err = websocket.JSON.Send(ws, response) 
     if err != nil { 
      fmt.Printf("Send failed: %s\n", err.Error()) 
      os.Exit(1) 
     } 
    } 
} 

func RunClient() { 
    fmt.Println("Starting Client") 
    ws, err := websocket.Dial(fmt.Sprintf("ws://%s/server", *address), "", fmt.Sprintf("http://%s/", *address)) 
    if err != nil { 
     fmt.Printf("Dial failed: %s\n", err.Error()) 
     os.Exit(1) 
    } 
    incomingMessages := make(chan Message) 
    go readClientMessages(ws, incomingMessages) 
    i := 0 
    for { 
     select { 
     case <-time.After(time.Duration(2e9)): 
      i++ 
      response := new(Message) 
      response.RequestID = i 
      response.Command = "Eject the hot dog." 
      err = websocket.JSON.Send(ws, response) 
      if err != nil { 
       fmt.Printf("Send failed: %s\n", err.Error()) 
       os.Exit(1) 
      } 
     case message := <-incomingMessages: 
      fmt.Println(message) 
     } 
    } 
} 

func readClientMessages(ws *websocket.Conn, incomingMessages chan Message) { 
    for { 
     var message Message 
     err := websocket.JSON.Receive(ws, &message) 
     if err != nil { 
      fmt.Printf("Error: %s\n", err.Error()) 
      return 
     } 
     incomingMessages <- message 
    } 
} 
+2

es muy prometedor, un servidor simple basado en eventos. Intentaré esta idea cuando tenga algo de tiempo, mientras tanto: +1 para tratar de ayudar – farnoy

+0

Si no quiere que se cierre la conexión, ¿por qué 'devuelve' si se encuentra un error ?, debería EOF en la señal de conexión ¿terminación? – Triztian