duanque3125
duanque3125
2016-02-15 17:49
浏览 731
已采纳

WebSocket-关闭握手大猩猩

Snippet from WebSocket RFC:

To Start the WebSocket Closing Handshake with a status code (Section 7.4) /code/ and an optional close reason (Section 7.1.6) /reason/, an endpoint MUST send a Close control frame, as described in Section 5.5.1, whose status code is set to /code/ and whose close reason is set to /reason/. Once an endpoint has both sent and received a Close control frame, that endpoint SHOULD Close the WebSocket Connection as defined in Section 7.1.1.

I am trying to do the Close Handshake using Gorilla WebSocket package with the following code:

Server:

// Create upgrader function
conn, err := upgrader.Upgrade(w, r, nil)

// If there is an error stop everything.
if err != nil {
    fmt.Println(err)
    return
}

for {
    // Read Messages
    _, _, err := conn.ReadMessage()
    // Client is programmed to send a close frame immediately...
    // When reading close frame resend close frame with same
    // reason and code
    conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(1000, "woops"))
    fmt.Println(err)
    break
}

Client:

d := &websocket.Dialer{}

conn, _, err := d.Dial("ws://localhost:8080", nil)

if err != nil {
    fmt.Println(err)
    return
}

go func() {
    for {
        // Read Messages
        _, _, err := conn.ReadMessage()

        if c, k := err.(*websocket.CloseError); k {
            if(c.Code == 1000) {
                // Never entering since c.Code == 1005
                fmt.Println(err)
                break
            }
        }
    }
}()

conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(1000, "woops"))

for {}

The server is reading the Close Frame as expected outputting the following:

websocket: close 1000 (normal): woops

However the client is like its stopping to read once it sends a close message. The ReadMessage continue to return error 1005. What am I doing wrong?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • duan3601
    duan3601 2016-02-15 21:59
    已采纳

    The server responds to a close frame with the code:

        c.WriteControl(CloseMessage, []byte{}, time.Now().Add(writeWait))
    

    This is translated to close code 1005 (no status received) by the client.

    The 1000 oops close frame written by the server is not seen by the client application because the websocket connection stops reading from network after receiving the first close frame.

    The client application should exit the loop when an error is returned from ReadMessage. There's no need to check for specific close codes.

    for {
        // Read Messages
        _, _, err := conn.ReadMessage()
        if err != nil {
            break
        }
    }
    

    Unrelated to the issue in the question, the server application should close the websocket connection after sending the close frame.

    Also unrelated to the issue in the question, use select {} instead of for {} to block the main goroutine. The former simply blocks the goroutine. The latter spins using CPU time.

    点赞 评论

相关推荐