处理多个WebSocket连接

时间:2019-06-13 19:51:04

标签: go websocket gorilla

我正在尝试创建一个程序,该程序将通过大猩猩网络套接字连接到多个服务器。我目前有一个程序,该程序将遍历服务器地址列表并创建一个新的goroutine,该例程将创建自己的Websocket.conn并处理读写操作。

问题在于,每次创建新的goroutine时,以前的goroutine都会被阻止,只有最后一个goroutine才能继续。我相信这是因为大猩猩网络套接字库阻止了每个gorotutine,但我可能会误会。

我尝试在服务器列表迭代器中放置一个计时器,每个goroutine都将正常运行,但是在用另一个地址创建新goroutine的那一刻,以前的goroutine被阻止了。

我的代码的相关部分:

在我的main.go

for _, server := range servers {
  go control(ctx, server, port)
}

control()


func control(ctx context.Context, server, port string) { 
  url := url.URL{
    Scheme: "ws",
    Host: server + ":" + port,
    Path: "",
  }
  conn, _, err := websocket.DefaultDialer.Dial(url.String(), nil)
  if err != nil {
    panic(err)
  }
  defer conn.Close()
  go sendHandler(ctx, conn)
  go readHandler(ctx, conn)
}

readHandler(ctx context.Context, conn *websocket.Con) {
  for {
    _, p, err := conn.ReadMessage(); if err != nil {
      panic(err)
    }
    select {
      case <-ctx.Done():
        goto TERM
      default:
        // do nothing
    }
  }
  TERM:
  // do termination  
}

sendHandler(ctx context.Context, conn *websocket.Con) {
  for _, msg := range msges {
    err = conn.WriteMessage(websocket.TextMessage, msg)
    if err != nil {
      panic(err)
    }
  }
  <-ctx.Done()
}

我删除了添加等待组和其他不必要代码段的部分。

所以我期望有3n个goroutine运行(其中n是服务器的数量)而没有阻塞,但是现在我只看到3个goroutine正在运行,这是服务器列表的最后一次迭代所调用的。 / p>

谢谢!

编辑14/06/2019:

我花了一些时间编写一个小的工作示例,在该示例中并未发生错误-没有一个线程相互阻塞。我仍然不确定是什么原因造成的,但这是我的一个小示例:

main.go

package main

import (
    "context"
    "fmt"
    "os"
    "time"
    "os/signal"
    "syscall"
    "sync"
    "net/url"
    "github.com/gorilla/websocket"
    )

func main() {
    servers := []string{"5555","5556", "5557"}
    comms := make(chan os.Signal, 1)
    signal.Notify(comms, os.Interrupt, syscall.SIGTERM)

    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    var wg sync.WaitGroup

    for _, server := range servers {
        wg.Add(1)
        go control(server,
                   ctx,
                   &wg)
    }

    <-comms
    cancel()
    wg.Wait()
}

func control(server string, ctx context.Context, wg *sync.WaitGroup) {
    fmt.Printf("Started control for %s\n", server)
    url := url.URL {
        Scheme: "ws",
        Host: "0.0.0.0" + ":" + server,
        Path: "",
    }
    conn, _, err := websocket.DefaultDialer.Dial(url.String(), nil)
    if err != nil {
        panic(err)
    }
    defer conn.Close()

    var localwg sync.WaitGroup

    localwg.Add(1)
    go sendHandler(ctx, conn, &localwg, server)
    localwg.Add(1)
    go readHandler(ctx, conn, &localwg, server)

    <- ctx.Done()
    localwg.Wait()
    wg.Done()
    return
}

func sendHandler(ctx context.Context, conn *websocket.Conn, wg *sync.WaitGroup, server string) {
    for i := 0; i < 50; i++ {
        err := conn.WriteMessage(websocket.TextMessage, []byte("ping"))
        if err != nil {
            panic(err)
        }
        fmt.Printf("sent msg to %s\n", server)
        time.Sleep(1 * time.Second)
    }
    <- ctx.Done()
    wg.Done()
}

func readHandler(ctx context.Context, conn *websocket.Conn, wg *sync.WaitGroup, server string) {
    for {

        select {

            case <- ctx.Done():
                wg.Done()
                return
            default:
                _, p, err :=  conn.ReadMessage()
                if err != nil {
                    wg.Done()
                    fmt.Println("done")
                }
                fmt.Printf("Got [%s] from %s\n", string(p), server)
        }
    }
}

我分别在5555、5556和5557上的服务器上使用dpallot的simple-websocket-server对它进行了测试。

1 个答案:

答案 0 :(得分:0)

这部分代码导致了问题:

conn, _, err := websocket.DefaultDialer.Dial(url.String(), nil)
if err != nil {
    panic(err)
}
defer conn.Close()
go sendHandler(ctx, conn)
go readHandler(ctx, conn)

您创建连接,推迟连接,开始另外两个goroutine,然后结束函数。由于您的推迟,功能端会关闭插座。