1 回答
TA贡献1788条经验 获得超4个赞
该websocket: close sent错误表明服务器向客户端发送了关闭消息。因为应用程序服务器代码不发送消息,所以连接必须发送消息以响应来自客户端的关闭消息。
关闭消息作为错误从 websocket 读取方法返回。因为没有记录任何消息,所以客户端一定发送了“离开”关闭消息(唯一没有记录的错误)。
当websocket连接返回错误时,读写goroutine关闭连接返回。连接未保持打开状态。
读取和写入 goroutine 不会检测到另一个已关闭连接,直到从连接上的方法调用返回错误。读取 goroutine 会快速检测到关闭的连接,因为它始终在读取,但写入 goroutine 可能会有延迟。这可能是应用程序的问题
要让写入 goroutine 快速退出,请使用通道向写入 goroutine 发出信号。有可能dataChan可用于此目的,但我不确定,因为该问题不包含有关如何管理频道的信息。假设通道可以使用,读取 goroutine 应该关闭dataChan。writer 应该检测到关闭的通道并退出 goroutine:
...
for {
select {
case data, ok := <-datachan:
if !ok {
// Done writing, return
return
}
ws.SetWriteDeadline(time.Now().Add(writeWait))
err := ws.WriteJSON(&data)
if err != nil {
conf.Log.Debugf("Failed to write data to Websocket: %v", err)
return
}
...
这是Gorilla Chat Example使用的方法。
如果dataChan不能使用,为此引入一个新的通道。在处理程序中创建通道并将通道传递给读写 goroutines:
done := make(chan struct{})
go allUserWebsocketWriter(ws, stop, datachan)
go PingResponse(ws, stop)
从读取 goroutine 返回时关闭通道:
func PingResponse(ws *websocket.Conn, done chan struct{}) {
defer close(done)
conf := storage.GetConfig()
...
在写gorountine的通道上选择:
...
for {
select {
case <-done:
return
case data := <-datachan:
ws.SetWriteDeadline(time.Now().Add(writeWait))
err := ws.WriteJSON(&data)
...
这导致写 goroutine 在读 goroutine 退出后快速退出。
这两种方法都降低了在连接上写入返回错误的可能性websocket: close sent,但它们并没有消除这种可能性。该错误是预期的,因为读取 goroutine 可以在写入 goroutine 写入消息之前关闭连接。
无论如何,证据是客户端正在关闭连接。未关闭的连接不是问题所在。
- 1 回答
- 0 关注
- 232 浏览
添加回答
举报