Обмен сообщениями WebSocket в Go
После перевода запроса обмен идет кадрами. Для обычного текста берут тип текстового сообщения из пакета библиотеки и срез байтов с английской фразой. Отправка и прием возвращают ошибку сети или протокола, их проверяют так же, как при записи в TCP.
Прием возвращает тип кадра, байты и ошибку. Для учебного эха достаточно прочитать один кадр, собрать ответ из префикса и текста клиента и отправить обратно до закрытия канала.
Сервер отвечает префиксом "echo: ",
клиент шлет "hello" и печатает
ответ:
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/gorilla/websocket"
)
func echoServer() {
upgrader := websocket.Upgrader{}
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
defer conn.Close()
_, msg, err := conn.ReadMessage()
if err != nil {
log.Println(err)
return
}
out := append([]byte("echo: "), msg...)
err = conn.WriteMessage(websocket.TextMessage, out)
if err != nil {
log.Println(err)
}
})
log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil))
}
func main() {
go echoServer()
time.Sleep(20 * time.Millisecond)
url := "ws://127.0.0.1:8080/ws"
conn, _, err := websocket.DefaultDialer.Dial(url, nil)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
err = conn.WriteMessage(websocket.TextMessage, []byte("hello"))
if err != nil {
log.Fatal(err)
}
_, reply, err := conn.ReadMessage()
if err != nil {
log.Fatal(err)
}
fmt.Println(string(reply))
}
На экране клиента "echo: hello".
Сервер прочитал текст, собрал ответ
и отправил его в том же соединении.
Клиент может сначала отправить другое слово, порядок шагов тот же:
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/gorilla/websocket"
)
func echoServer() {
upgrader := websocket.Upgrader{}
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
defer conn.Close()
_, msg, err := conn.ReadMessage()
if err != nil {
return
}
out := append([]byte("echo: "), msg...)
_ = conn.WriteMessage(websocket.TextMessage, out)
})
log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil))
}
func main() {
go echoServer()
time.Sleep(20 * time.Millisecond)
conn, _, err := websocket.DefaultDialer.Dial("ws://127.0.0.1:8080/ws", nil)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
_ = conn.WriteMessage(websocket.TextMessage, []byte("ping"))
_, reply, err := conn.ReadMessage()
if err != nil {
log.Fatal(err)
}
fmt.Println(string(reply))
}
Дано сообщение клиента:
line := "ask"
На сервере после чтения текстового кадра
отправьте клиенту строку "reply: ask",
если в байтах было ровно line.
Дан путь:
path := "/ws"
Клиент отправляет "go" на
ws://127.0.0.1:8080 с этим
путем; сервер возвращает "echo: go".
Опишите порядок чтения и отправки на
стороне сервера.
Скажите, почему для английской фразы
удобно передавать []byte("hello"),
а не один символ типа rune.