【问题标题】:How to communicate between a http request handler and websocket server using gin and gorilla/websocket?如何使用 gin 和 gorilla/websocket 在 http 请求处理程序和 websocket 服务器之间进行通信?
【发布时间】:2021-10-16 12:09:15
【问题描述】:

我想创建一个实时 API。 Github Link of current code

将有两种类型的用户 A 和 B。 用户 A 可以使用 websocket 连接到服务以查看实时更新。 用户 B 只能发出 http 请求将数据推送到 mongodb。我一直在关注this tutorial。在本教程中使用了 sqlitedb 和 redis pub/sub,但我不想使用它。

slotServer.go

...

func (server *WsServer) Run() {
    gb := *models.GetInstanceGlobal()
    for {
        select {

        case client := <-server.register:
            server.registerClient(client)

        case client := <-server.unregister:
            server.unregisterClient(client)
        case message := <-server.broadcast:
            server.broadcastToClient(message)
        case message := <-gb.Channel:           
            server.createRoomAndBroadCast(message)
        }

    }
}
...

func (server *WsServer) createRoom(name string) *Room {
    room := NewRoom(name)
    go room.RunRoom()
    server.rooms[room] = true
    return room
}

func (server *WsServer) createRoomAndBroadCast(name string) {
    room := server.createRoom(name)
    var roomList []string
    for r := range server.rooms {
        roomList = append(roomList, r.GetName())
    }

    addRoomReply := models.AddRoomReply{
        RoomList:  roomList,
        AddedRoom: room.GetName(),
    }

    addReply := MessageAddRoom{
        Data:   addRoomReply,
        Action: "room-add-success",
    }

    server.broadcast <- addReply.encode()
}

我正在尝试收听全球频道。如果一个字符串被推送到它,一个函数 createRoomAndBroadCast 将被调用。

models.go

....
type GlobalChannel struct {
    Channel chan string
}

func GetInstanceGlobal() *GlobalChannel {
    return &GlobalChannel{
        Channel: make(chan string),
    }
}

我正在 POST 消息处理程序中写入此频道

room.go

...
    //add room to mongo
    if err := db.CreateRoom(&room); err != nil {    
        ctx.JSON(http.StatusBadGateway, gin.H{
        "data": err,
    })
    return
    }
    //write it to channel
    gb := models.GetInstanceGlobal()
    gb.Channel <- *room.Name
    // send reponse to user
    ctx.JSON(http.StatusCreated, gin.H{
        "data": "Room Created Successfully",
    })
...

但我的发帖请求卡在 gb := models.GetInstanceGlobal() 行 在日志中,我看到以下消息

redirecting request 307: /api/v1/room/ --> /api/v1/room/

我不明白是我做错了什么还是我的逻辑完全错误。

【问题讨论】:

    标签: go websocket publish-subscribe gorilla


    【解决方案1】:

    我开始阅读有关 golang 中通道如何工作的信息,感谢 this post 发现在通道中提及缓冲区限制非常重要。

    如果 ch 没有缓冲,那么 ch

    所以我改变了

    models.go

    //Channel: make(chan string),
    Channel: make(chan string,100),
    

    它开始传输消息。

    【讨论】:

      【解决方案2】:

      我只会评论您在此处显示的代码,而不是整体设计。

      func GetInstanceGlobal() *GlobalChannel {
          return &GlobalChannel{
              Channel: make(chan string),
          }
      }
      

      这可能是对频道的误解。虽然您已将其命名为 GetInstanceGlobal,但实际上每次调用它时都会返回一个全新的频道。因此,如果一侧调用它然后尝试接收消息,另一侧调用它并推送消息,则两侧将是不同的通道,并且永远不会通信。这解释了为什么您的推送会永远阻塞。它还解释了为什么当您添加 100 以使其成为似乎解除阻塞的缓冲通道时。但实际上你所做的只是让它在推送端建立多达 100 条排队消息并最终再次阻塞。接收器仍在自己的频道上。

      代码暗示的可能是您希望创建一次全局、返回并共享它。我不会在这里讨论全局变量的设计问题。但对于您的情况,它可能看起来像这样:

      var globalChannel *GlobalChannel
      
      func GetInstanceGlobal() *GlobalChannel {
          if globalChannel == nil {
              globalChannel = &GlobalChannel{
                  Channel: make(chan string),
              }
          } 
          return globalChannel
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-27
        • 1970-01-01
        • 1970-01-01
        • 2014-03-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-16
        相关资源
        最近更新 更多