Gorilla websocket error: close 1007 Illegal UTF-8 Sequence
Gorilla websocket error: close 1007 Illegal UTF-8 Sequence
我正在尝试为 GlassFish 实现一个 websocket 代理服务器。如果我尝试连接多个客户端,我会收到错误消息:
ReadMessage Failed: websocket: close 1007 Illegal UTF-8 Sequence.
我确定 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)
}
}
}
}
总结我的评论作为答案:
当您写入客户端时,您是从 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(...)
所以可能发生的情况是两个独立的 goroutines 同时写入同一个客户端。您应该通过在 WriteMessage
方法实现中添加互斥锁来保护您的客户端免受它的影响。
顺便说一句,实际上不是使用互斥锁来保护此方法,而是更好、更 "go-ish" 的方法是使用通道来写入消息,并为每个客户端使用一个 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)
}
}()
}
并且在创建新的客户端实例时,只需启动写入循环
我正在尝试为 GlassFish 实现一个 websocket 代理服务器。如果我尝试连接多个客户端,我会收到错误消息:
ReadMessage Failed: websocket: close 1007 Illegal UTF-8 Sequence.
我确定 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)
}
}
}
}
总结我的评论作为答案:
当您写入客户端时,您是从 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(...)
所以可能发生的情况是两个独立的 goroutines 同时写入同一个客户端。您应该通过在 WriteMessage
方法实现中添加互斥锁来保护您的客户端免受它的影响。
顺便说一句,实际上不是使用互斥锁来保护此方法,而是更好、更 "go-ish" 的方法是使用通道来写入消息,并为每个客户端使用一个 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)
}
}()
}
并且在创建新的客户端实例时,只需启动写入循环