大猩猩websocket错误:关闭1007非法UTF-8序列

时间:2015-07-09 08:45:26

标签: go websocket glassfish gorilla

我正在尝试为GlassFish实现websocket代理服务器。如果我尝试连接多个客户端,我会收到错误:

  

ReadMessage失败:websocket:close 1007非法UTF-8序列。

我确定GlassFish服务器发送正确的数据,因为同一服务器与使用node.js实现的另一个代理服务器正常工作。

func GlassFishHandler(conn *websocket.Conn){

    defer conn.Close()

    conn.SetReadDeadline(time.Now().Add(1000 * time.Second))
    conn.SetWriteDeadline(time.Now().Add(1000 * time.Second))

    fmt.Println("WS-GOLANG PROXY SERVER: Connected to GlassFish")

    for {

        messageType, reader, err := conn.NextReader()

        if err != nil {
            fmt.Println("ReadMessage Failed: ", err) // <- error here
        } else {

            message, err := ioutil.ReadAll(reader)
            if (err == nil && messageType == websocket.TextMessage){

                var dat map[string]interface{}
                if err := json.Unmarshal(message, &dat); err != nil {
                    panic(err)
                } 

                // get client destination id
                clientId := dat["target"].(string)

                fmt.Println("Msg from GlassFish for Client: ", dat);

                // pass through
                clients[clientId].WriteMessage(websocket.TextMessage, message)
            }
        }
    }
}

1 个答案:

答案 0 :(得分:3)

总结我的评论作为答案:

当您写入客户端时,您从GlassFish消息中获取clientId,从地图中获取客户端,然后写入它 - 基本上是clients[clientId].WriteMessage(...)

虽然您的地图访问可以是线程安全的,但写入不是,因为这可以看作:

// map access - can be safe if you're using a concurrent map
client := clients[clientId]

// writing to a client, not protected at all
client.WriteMessage(...)

所以可能发生的事情是两个独立的goroutine同时写入同一个客户端。您应该通过在WriteMessage方法实现中添加互斥锁来保护您的客户端。

实际上BTW不是用互斥体来保护这种方法,而是用更好的,更好的,更好的方式来保护这种方法。方法是使用通道来编写消息,以及每个客户端的goroutine,它从通道消耗并写入实际套接字。

所以在客户端结构中,我做了类似的事情:

type message struct {
   msgtype string
   msg string
 }

type client struct {
    ...
    msgqueue chan *message
}


func (c *client)WriteMessage(messageType, messageText string) {
   // I'm simplifying here, but you get the idea
   c.msgqueue <- &message{msgtype: messageType, msg: messageText}
}

func (c *client)writeLoop() {
   go func() {
       for msg := ragne c.msgqueue {
           c.actuallyWriteMessage(msg)
       }
   }()
}

并且在创建新的客户端实例时,只需启动写循环