2016-12-01 66 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