Go WebSocket-结束握手大猩猩

Go WebSocket-结束握手大猩猩,go,websocket,handshake,gorilla,Go,Websocket,Handshake,Gorilla,来自WebSocket RFC的代码段: 要使用状态代码(第7.4节)/code/和可选关闭原因(第7.1.6节)/reason/启动WebSocket关闭握手,端点必须发送关闭控制帧,如第5.5.1节所述,其状态代码设置为/code/,关闭原因设置为/reason/。一旦端点发送和接收到关闭控制帧,该端点应按照第7.1.1节中的定义关闭WebSocket连接 我正在尝试使用具有以下代码的软件包进行近距离握手: 服务器: // Create upgrader function conn, err

来自WebSocket RFC的代码段:

要使用状态代码(第7.4节)/code/和可选关闭原因(第7.1.6节)/reason/启动WebSocket关闭握手,端点必须发送关闭控制帧,如第5.5.1节所述,其状态代码设置为/code/,关闭原因设置为/reason/。一旦端点发送和接收到关闭控制帧,该端点应按照第7.1.1节中的定义关闭WebSocket连接

我正在尝试使用具有以下代码的软件包进行近距离握手:

服务器:

// 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
}
客户:

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 {}
服务器正在按预期读取闭合帧,并输出以下内容:

websocket:close 1000(正常):低音


然而,客户机就像它在发送关闭消息后停止阅读一样。
ReadMessage
继续返回错误1005。我做错了什么?

服务器用以下命令响应闭合帧:

客户端将其转换为关闭代码1005(未收到状态)

客户端应用程序看不到服务器写入的1000 oops关闭帧,因为websocket连接在收到第一个关闭帧后停止从网络读取

当ReadMessage返回错误时,客户端应用程序应退出循环。不需要检查特定的关闭代码

for {
    // Read Messages
    _, _, err := conn.ReadMessage()
    if err != nil {
        break
    }
}
与问题中的问题无关,服务器应用程序应该在发送关闭帧后关闭websocket连接


同样与问题中的问题无关,使用
select{}
而不是
for{}
来阻止主goroutine。前者简单地阻止了goroutine。后者使用CPU时间旋转。

我知道这个答案很旧,但这似乎是错误的:“使用
选择{}
而不是
for{}
。前者永远阻塞。后者永远旋转。”OP不是从通道读取。这就是选择的目的
conn.ReadMessage()
已被阻止。@ArturSapek注释是指在OP的代码末尾对{}使用了
。{}
构造的
消耗CPU时间。
select{}
将简单地阻塞。调用
conn.ReadMessage()
不会阻止主goroutine。
for {
    // Read Messages
    _, _, err := conn.ReadMessage()
    if err != nil {
        break
    }
}