WebSocket - Menutup Jabat Tangan Gorila

Cuplikan dari WebSocket RFC:

Untuk Memulai Jabat Tangan Penutupan WebSocket dengan kode status (Bagian 7.4) /code/ dan alasan penutupan opsional (Bagian 7.1.6) /alasan/, titik akhir HARUS mengirimkan bingkai kontrol Tutup, seperti yang dijelaskan di Bagian 5.5.1, yang kode statusnya disetel ke /code/ dan alasan dekatnya disetel ke /reason/. Setelah titik akhir mengirim dan menerima bingkai kontrol Tutup, titik akhir tersebut HARUS Menutup Koneksi WebSocket seperti yang ditentukan dalam Bagian 7.1.1.

Saya mencoba melakukan Close Handshake menggunakan paket Gorilla WebSocket dengan kode berikut:

pelayan:

// 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
}

Klien:

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 {}

Server membaca Close Frame seperti yang diharapkan dan menghasilkan keluaran berikut:

websocket: tutup 1000 (normal): ups

Namun klien seperti berhenti membaca setelah mengirimkan pesan dekat. ReadMessage terus mengembalikan kesalahan 1005. Apa yang saya lakukan salah?


person Kim Byer    schedule 15.02.2016    source sumber


Jawaban (1)


Server merespons close frame dengan kode:

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

Ini diterjemahkan menjadi kode penutup 1005 (tidak ada status diterima) oleh klien.

Close frame 1000 oops yang ditulis oleh server tidak terlihat oleh aplikasi klien karena koneksi websocket berhenti membaca dari jaringan setelah menerima close frame pertama.

Aplikasi klien harus keluar dari loop ketika kesalahan dikembalikan dari ReadMessage. Tidak perlu memeriksa kode penutupan tertentu.

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

Tidak terkait dengan masalah dalam pertanyaan, aplikasi server harus menutup koneksi websocket setelah mengirim close frame.

Juga tidak terkait dengan masalah dalam pertanyaan, gunakan select {} daripada for {} untuk memblokir goroutine utama. Yang pertama hanya memblokir goroutine. Yang terakhir berputar menggunakan waktu CPU.

person Cerise Limón    schedule 15.02.2016
comment
Saya tahu jawaban ini sudah lama, tetapi sepertinya ini salah: gunakan select {} daripada for {}. Mantan blok selamanya. Yang terakhir berputar selamanya. OP tidak membaca dari chans. Itulah gunanya pilih. conn.ReadMessage() sudah memblokir. - person Artur Sapek; 17.10.2017
comment
@ArturSapek Komentar tersebut mengacu pada penggunaan for {} di akhir kode OP. Konstruksi for {} membakar waktu CPU. select {} hanya akan memblokir. Panggilan ke conn.ReadMessage() tidak memblokir goroutine utama. - person Cerise Limón; 17.10.2017