大猩猩 WebSocket 错误:关闭 1007 非法的 UTF-8 序列。

huangapple go评论108阅读模式
英文:

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)
            }
        }
    }
}

以上是你要翻译的内容。

英文:

I'm trying to implement a websocket proxy server for GlassFish. If I try to connect more than one client I'm getting error:

> ReadMessage Failed: websocket: close 1007 Illegal UTF-8 Sequence.

I'm sure the GlassFish server sending right data, because the same server works properly with another proxy server implemented with 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(&quot;WS-GOLANG PROXY SERVER: Connected to GlassFish&quot;)
	
	for {
		
		messageType, reader, err := conn.NextReader()
		
		if err != nil {
			fmt.Println(&quot;ReadMessage Failed: &quot;, err) // &lt;- error here
		} else {

			message, err := ioutil.ReadAll(reader)
			if (err == nil &amp;&amp; messageType == websocket.TextMessage){
				
				var dat map[string]interface{}
				if err := json.Unmarshal(message, &amp;dat); err != nil {
			        panic(err)
			    } 
                
                // get client destination id
                clientId := dat[&quot;target&quot;].(string)
				
				fmt.Println(&quot;Msg from GlassFish for Client: &quot;, dat);

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

答案1

得分: 3

总结我的评论作为答案:

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

虽然你的映射访问可能是线程安全的,但写入不是,因为可以看作是:

// 映射访问 - 如果你使用并发映射可能是安全的
client := clients[clientId]

// 写入客户端,没有任何保护
client.WriteMessage(...)

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

顺便说一句,实际上,与其用互斥锁保护这个方法,更好、更符合Go语言风格的方法是使用通道来写入消息,并为每个客户端启动一个goroutine来从通道中消费并写入实际的套接字。

所以在client结构体中,我会这样做:

type message struct {
   msgtype string
   msg string
 }

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


func (c *client)WriteMessage(messageType, messageText string) {
   // 这里我简化了,但你明白我的意思
   c.msgqueue <- &message{msgtype: messageType, msg: messageText}
}

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

当创建一个新的客户端实例时,只需启动写循环。

英文:

Summing up my comments as an answer:

When you are writing to the client, you are taking the clientId from the GlassFish message, fetching the client from a map, and then writing to it - basically clients[clientId].WriteMessage(...).

While your map access can be thread safe, writing is not, as this can be seen as:

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

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

So what's probably happening is that two separate goroutines are writing to the same client at the same time. You should protect your client from it by adding a mutex in the WriteMessage method implementation.

BTW actually instead of protecting this method with a mutex, a better, more "go-ish" approach would be to use a channel to write the message, and a goroutine per client that consumes from the channel and writes to the actual socket.

So in the client struct I'd do something like this:

type message struct {
   msgtype string
   msg string
 }

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


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

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

and when creating a new client instance, just launch the write loop

huangapple
  • 本文由 发表于 2015年7月9日 16:45:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/31312458.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定