去websockets eof

时间:2012-02-16 19:00:50

标签: io websocket go eof

我正在尝试创建一个简单的命令转发器来将我的家用计算机连接到我拥有的服务器,以便我可以将命令推送到我的服务器而我的家用电脑就可以获得它。这些命令是我的下载器的简单暂停/恢复。我的设计是,在服务器上,我运行一个集线器实例,它创建一个传递命令的窗口和一个后端窗口,将这些命令传递给我的电脑。我将这两个“窗口”与一个频道绑定,他们运行服务器。当客户端连接并向集线器发送消息时,它会通过通道流到后端窗口,然后流到真正的后端(在我的家用电脑上)。当后端响应集线器上的后端窗口时,集线器会将结果打印回客户端。

使用这种方法,只有第一条消息通过并与我的下载程序一起使用。每次收到消息以使其正常工作时,我必须从家用电脑的后端重新连接集线器。我不认为这是websockets的正确方法,所以我在这里。在一次成功的请求之后(当后端完成它的工作并回复结果时),它会在EOF错误的情况下永远循环。

代码的重要部分是:

如果你把源代码放在你的GOPATH中(我正在为支持现代websockets的tip版本开发它),要编译它: go build gosab/cmd,运行它:

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

要将消息传递到集线器,请使用此javascript:

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

那我该如何处理呢?渠道是两种不同请求之间沟通的好方法吗?

1 个答案:

答案 0 :(得分:7)

我很惊讶你没有得到答案。

您需要做的是类似下面的代码。当您收到传入的websocket连接时,会为该连接生成一个新的goroutine。如果你让goroutine结束,它将断开websocket客户端。

我假设您不一定要在同一台计算机上运行客户端和服务器。如果你一直都是,那么最好通过渠道等内部进行通信,而不是使用websockets或网络端口。我只提到这个,因为我不完全确定你使用的是什么。我只希望我回答你问题的正确部分。

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
    }
}