2012-02-16 28 views
6

我試圖做一個簡單的命令轉發器來連接我的家用電腦到我自己的服務器上,這樣我就可以將命令推送到我的服務器,並且我的家用電腦也可以得到它。這些命令對於我的下載程序是簡單的暫停/恢復。我的設計是,在服務器上,我運行一個集線器實例,它創建一個傳遞命令的窗口和一個後端窗口,將這些命令傳遞到我的電腦。我將這兩個「窗口」綁定到一個頻道,他們運行一臺服務器。當客戶端連接併發送消息到集線器時,它會通過一個通道傳輸到後端窗口,然後傳輸到真實的後端(在我的家用電腦上)。當後端響應集線器上的後端窗口時,集線器將結果打印回客戶端。go websockets eof

使用這種方法,只有第一條消息通過並與我的下載程序一起工作。每當我收到一條消息以使其正常工作時,我必須將我的家用計算機的後端與集線器重新連接。我不認爲這是使用websockets的正確方式,所以我在這裏。在一個成功的請求(當後端完成它的工作並回復結果時)之後,它會永久性地出現EOF錯誤。

代碼的重要部分是:

如果你把源在GOPATH(我開發它的小費去支持現代websockets的版本),編譯它: go build gosab/cmd,運行它:

  • ./cmd -mode="hub"樞紐
  • ./cmd -mode="backend" --address="localhost:8082"後端

要傳遞消息到輪轂上,使用此javascript:

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

那麼我該如何處理呢?渠道是兩種不同請求之間溝通的好方法嗎?

+0

重塑車輪,也許是爲了好玩嗎?聽起來很像Salt:http://saltstack.org/或木偶實驗室木偶:http://docs.puppetlabs.com/mcollective/index.html – djangofan 2012-02-21 00:27:01

+0

很好的鏈接,但我想自己實現這樣的東西 – farnoy 2012-02-21 07:10:36

+0

我使用類似的東西(在websockets中使用瀏覽器 - 服務器通信的遊戲服務器),所以我知道如何去做,但我不明白這裏真正的問題。如果只是「渠道是溝通的好方法」,那麼答案是肯定的。 – 2012-04-25 07:05:45

回答

7

我很驚訝你還沒有收到答覆。

你需要做的就像下面的代碼。當您收到傳入的websocket連接時,會爲此連接生成一個新的goroutine。如果你讓那個goroutine結束,它將斷開websocket客戶端。

我假設你不一定會在同一臺計算機上運行客戶端和服務器。如果你總是這樣,那麼最好是通過頻道或者類似的渠道進行溝通,而不是使用網絡插口或網絡端口。我只提到這一點,因爲我不完全確定你使用的是什麼。我只希望我回答你問題的正確部分。

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

看起來非常有前途,它是一個簡單的事件驅動型服務器。我會嘗試這個想法,當我得到一些時間,同時:+1幫助 – farnoy 2012-06-02 17:11:01

+0

如果你不想連接被關閉爲什麼你'返回'如果遇到錯誤?,應該EOF連接信號終止? – Triztian 2016-04-29 18:01:05