2016-12-01 68 views
0

我有一个Websocket服务器写在go与包github.com/gorilla/websocketwebsocket客户端onmessage刷新浏览器后破坏

服务器有2个用于接收和发送消息的环路。在HTTP处理程序的实现如下所示:

upgrader, errChan := websocket.Upgrader{}, make(chan error) 

ws, err := upgrader.Upgrade(w, r, nil) 
if err != nil { 
    http.Error(w, err.Error(), http.StatusInternalServerError) 
    return 
} 

// incoming messages 

go func() { 
    for { 
     message := Message{} 
     if err := ws.ReadJSON(&message); err != nil { 
      errChan <- err 
     } 
     handleMessage(message) 
    } 
}() 

// outgoing messages 

go func() { 
    for { 
     message := <-global.outgoingMessage 
     if err = ws.WriteMessage(websocket.TextMessage, message); err != nil { 
      errChan <- err 
     } 
    } 
}() 

err = <- errChan 
ws.Close() 

客户端应用程序使用反应,该应用程序使用的消息作为状态。当应用程序启动时,websocket连接建立,并且onopen回调触发对初始数据的请求。响应被用于应用程序状态的onmessage捕获。实现如下所示:

var ws = new WebSocket("ws://localhost:8080/app") 

ws.onerror = function(err) { 
    alert(err) 
} 
ws.onmessage = function(m) { 
    var state = JSON.parse(m.data) 
    global.app.setState(state) 
} 
ws.onopen = function() { 
    ws.send('{"type":"init"}') 
} 

有了这个设置,我已经注意到是我第一次火起来的应用程序和浏览页面的一切工作正常。一旦我刷新浏览器,它不再有效。我可以拨打ws.send('{"type":"init"}')并查看服务器发送的响应,但onmessage回调不会被触发。经过多次尝试呼叫ws.send('{"type":"init"}')后,onmessage最终会被调用一次,并且应用状态被加载。如果我杀了并重新启动应用程序,则会发生相同的行为。

想法?

+0

该应用程序泄漏goroutines。看到[这个问题](http://stackoverflow.com/questions/38090545/are-goroutines-garbage-collected-together-with-their-channels)的解释。多个输出程序从'global.outgoingMessage'接收吗?如果是这样,确保足够的消息发送到'global.outgoingMessage'以满足所有正在运行的输出例程? –

+0

@MellowMarmot你是对的。 'global.outgoingMessage'只能从这个处理程序中接收,但它是一个全局通道,所以当刷新浏览器websocket连接时,上一个连接仍在通道上监听。如果你发布答案,我会接受它。谢谢! – believesInSanta

回答

0

看起来好像所有的输出例程都从单通道global.outgoingMessage接收,并且没有足够的消息发送到此通道以满足所有正在运行的输出例程。

如果应用程序的目的是向所有连接的客户端广播,那么我建议遵循Gorilla chat example中的集线器模式。

另外:应用程序泄漏goroutines。有关说明,请参阅this question