Sockets Golang-扩展websocket客户端以实现到不同服务器的多个连接

Sockets Golang-扩展websocket客户端以实现到不同服务器的多个连接,sockets,go,scaling,Sockets,Go,Scaling,我有一个websocket客户端。实际上,它比下面显示的基本代码复杂得多。 我现在需要扩展这个客户端代码,以打开到多个服务器的连接。最终,从服务器接收消息时需要执行的任务是相同的。 处理这个问题的最佳方法是什么? 如上所述,接收消息时执行的实际代码比示例中显示的要复杂得多 package main import ( "flag" "log" "net/url" "os" "os/signal" "t

我有一个websocket客户端。实际上,它比下面显示的基本代码复杂得多。 我现在需要扩展这个客户端代码,以打开到多个服务器的连接。最终,从服务器接收消息时需要执行的任务是相同的。 处理这个问题的最佳方法是什么? 如上所述,接收消息时执行的实际代码比示例中显示的要复杂得多

package main

import (
        "flag"
        "log"
        "net/url"
        "os"
        "os/signal"
        "time"

        "github.com/gorilla/websocket"
)

var addr = flag.String("addr", "localhost:1234", "http service address")

func main() {
        flag.Parse()
        log.SetFlags(0)

        interrupt := make(chan os.Signal, 1)
        signal.Notify(interrupt, os.Interrupt)

        // u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"}
        u := url.URL{Scheme: "ws", Host: *addr, Path: "/"}
        log.Printf("connecting to %s", u.String())

        c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
        if err != nil {
                log.Fatal("dial:", err)
        }
        defer c.Close()

        done := make(chan struct{})

        go func() {
                defer close(done)
                for {
                        _, message, err := c.ReadMessage()
                        if err != nil {
                                log.Println("read:", err)
                                return
                        }
                        log.Printf("recv: %s", message)
                }
        }()

        ticker := time.NewTicker(time.Second)
        defer ticker.Stop()

        for {
                select {
                case <-done:
                        return
                case t := <-ticker.C:
                        err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
                        if err != nil {
                                log.Println("write:", err)
                                return
                        }
                case <-interrupt:
                        log.Println("interrupt")

                        // Cleanly close the connection by sending a close message and then
                        // waiting (with timeout) for the server to close the connection.
                        err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
                        if err != nil {
                                log.Println("write close:", err)
                                return
                        }
                        select {
                        case <-done:
                        case <-time.After(time.Second):
                        }
                        return
                }
        }
}
主程序包
进口(
“旗帜”
“日志”
“网络/网址”
“操作系统”
“操作系统/信号”
“时间”
“github.com/gorilla/websocket”
)
var addr=flag.String(“addr”、“localhost:1234”、“http服务地址”)
func main(){
flag.Parse()
log.SetFlags(0)
中断:=接通(切换操作信号,1)
信号通知(中断,操作系统中断)
//u:=url.url{Scheme:“ws”,主机:*地址,路径:“/echo”}
u:=url.url{Scheme:“ws”,主机:*地址,路径:“/”}
log.Printf(“连接到%s”,u.String())
c、 _u,err:=websocket.DefaultDialer.Dial(u.String(),nil)
如果错误!=零{
log.Fatal(“拨号:”,错误)
}
推迟c.结束()
完成:=make(chan结构{})
go func(){
延迟关闭(完成)
为了{
_,消息,错误:=c.ReadMessage()
如果错误!=零{
log.Println(“读取:”,错误)
返回
}
log.Printf(“记录:%s”,消息)
}
}()
股票代码:=time.NewTicker(time.Second)
延迟停止
为了{
挑选{

案例与每台不同服务器的通信是否完全独立于其他服务器?如果是,我会以如下方式进行:

  • 主要是创建一个带有取消功能的
  • 在主轨迹中创建激发的goroutines
  • 对于每个服务器,添加到waitgroup,从传递上下文和waitgroup引用的主函数启动一个新的goroutine
  • main进入for/select循环,监听for信号,如果有人到达,则调用cancelfunc并等待waitgroup
  • main还可以收听goroutines的结果,如果goroutines不应该直接打印结果,则可以自己打印结果
  • 正如我们所说,每个goroutine都有wg的引用、上下文以及可能返回结果的chan。现在,如果goroutine必须只做一件事,或者需要做一系列事情,那么方法就会分裂。对于第一种方法
  • 如果只需要做一件事,我们将遵循所描述的方法(注意,为了异步,他将启动一个新的goroutine来执行DoSomething()步骤,该步骤将在通道上返回结果) 这使得它能够在任何时候接受取消信号。这取决于您决定您希望如何不阻塞以及您希望如何及时响应取消信号。将a上下文关联传递给goroutines的好处还在于,您可以调用大多数库f的启用上下文的版本函数。例如,如果您希望拨号的超时时间为1分钟,您可以从传递的超时时间创建一个新的上下文,然后使用该超时时间创建拨号上下文。这允许拨号在超时时间或父(您在main中创建的)上下文的cancelfunc被调用时停止
  • 如果需要做更多的事情,我通常更喜欢使用goroutine做一件事,让它在下一步执行时调用一个新的goroutine(通过管道传递所有引用)并退出

这种方法可以很好地进行取消扩展,并且能够在任何步骤停止管道,并且对于可能需要太长时间的步骤,可以很容易地支持dealine上下文。

修改中断处理以在中断时关闭通道。这允许多个goroutine通过等待通道关闭来等待事件

shutdown := make(chan struct{})
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
go func() {
    <-interrupt
    log.Println("interrupt")
    close(shutdown)
}()

上面的代码经过编辑,可以在Gorilla的echo示例服务器上运行。

谢谢。帮了我很大的忙。我已经将两个答案都标记为correc.t非常感谢。这正是我想要的。
func connect(u string, shutdown chan struct{}, wg *sync.WaitGroup) {
    defer wg.Done()

    log.Printf("connecting to %s", u)
    c, _, err := websocket.DefaultDialer.Dial(u, nil)
    if err != nil {
        log.Fatal("dial:", err)
    }
    defer c.Close()

    done := make(chan struct{})

    go func() {
        defer close(done)
        for {
            _, message, err := c.ReadMessage()
            if err != nil {
                log.Println("read:", err)
                return
            }
            log.Printf("recv: %s", message)
        }
    }()

    ticker := time.NewTicker(time.Second)
    defer ticker.Stop()

    for {
        select {
        case <-done:
            return
        case t := <-ticker.C:
            err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
            if err != nil {
                log.Println("write:", err)
                return
            }
        case <-shutdown:
            // Cleanly close the connection by sending a close message and then
            // waiting (with timeout) for the server to close the connection.
            err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
            if err != nil {
                log.Println("write close:", err)
                return
            }
            select {
            case <-done:
            case <-time.After(time.Second):
            }
            return
        }
    }
}
var wg sync.WaitGroup
for _, u := range endpoints { // endpoints is []string 
                              // where elements are URLs 
                              // of endpoints to connect to.
    wg.Add(1)
    go connect(u, shutdown, &wg)
}
wg.Wait()