【问题标题】:go websockets eof去 websockets eof
【发布时间】:2012-02-16 19:00:50
【问题描述】:

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

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

代码的重要部分是:

如果你将源代码放在你的 GOPATH 中(我正在为 go 的尖端版本开发它以支持现代 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")

那我该如何处理呢?通道是在两个不同请求之间进行通信的好方法吗?

【问题讨论】:

  • 重新发明轮子,也许是为了好玩?听起来很像 Salt:saltstack.org 或 Puppet Labs Marionette:docs.puppetlabs.com/mcollective/index.html
  • 不错的链接,但我想自己实现这样的东西
  • 我使用类似的东西(在 websockets 中具有浏览器-服务器通信的游戏服务器),所以我知道如何去做,但我不明白这里真正的问题是什么。如果只是“渠道是一种很好的交流方式”,答案是肯定的。
  • 你希望我发布我的 websocket go 服务器的主要代码作为答案(太大而无法评论)吗?我觉得你必须做一些非常相似的事情(更简单,因为你不会为特定桌子的所有玩家更新游戏(玩家坐下来玩或观察)。
  • 抱歉不活动,我真正的问题/问题是,当您将消息传递给代理时,问题是如何将它们提供给另一个 websocket 连接(这里 - 后端)。我认为频道不适合这里,不可阻塞的队列会更好。我已经实现了这个逻辑,这个程序在 node.js 中带有浏览器和后端的 ruby​​,都使用 Faye,所以我不再需要这个问题的答案了。我必须在基于队列的消息中继中重新实现这个 go 代码,但我没有时间去做,因为有很多引擎可以进行这种通信

标签: io websocket go eof


【解决方案1】:

我很惊讶你没有收到这个答案。

您需要做的是类似于下面的代码。当您收到传入的 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
    }
}

【讨论】:

  • 看起来很有前途,一个简单的事件驱动服务器。当我有时间时,我会尝试这个想法,同时:+1 试图提供帮助
  • 如果你不希望连接被关闭为什么你return如果遇到错误?,连接信号终止时应该EOF吗?
猜你喜欢
  • 2020-08-12
  • 1970-01-01
  • 2014-01-12
  • 1970-01-01
  • 2013-07-20
  • 2015-09-08
  • 2015-04-10
  • 1970-01-01
相关资源
最近更新 更多