Как использовать сегодняGo
создание языкаWebSocket
услуги, о которых кратко рассказано в первых двух частях статьиWebSocket
соглашение иGo
Как создается стандартная библиотекаWebSocket
Служить. В третьей части практической части мы использовалиgorilla/websocket
Библиотеки помогают нам быстро строитьWebSocket
Сервисы, которые помогают инкапсулировать использованиеGo
Реализация стандартной библиотекиWebSocket
Базовая логика, связанная с услугами, позволяет нам освободиться от громоздкого базового кода и быстро строить в соответствии с потребностями бизнеса.WebSocket
Служить.
Исходный код для каждой статьи серии Web Programming сыграл соответствующую версию пакета для вашей справки. Отвечать
gohttp10
Получить исходный код этой статьи
Введение в веб-сокеты
WebSocket
протокол связи через единыйTCP
Соединение обеспечивает полнодуплексный канал связи. иHTTP
по сравнению с,WebSocket
Вам не нужно отправлять запрос, чтобы получить ответ. Это позволяет двунаправленный поток данных, так что вы просто ждете сообщения от сервера. когдаWebsocket
Он отправит вам сообщение, когда он будет доступен. Для сервисов, требующих непрерывного обмена данными (таких как мессенджеры, онлайн-игры и торговые системы в реальном времени),WebSocket
является хорошим решением.WebSocket
Соединение запрашивается браузером, отвечает сервером, и соединение устанавливается. Этот процесс широко известен как рукопожатие. WebSocket
Специальные заголовки в : требуют только одного рукопожатия между браузером и сервером для установления соединения, которое будет оставаться активным в течение всего времени существования.WebSocket
решать многие в режиме реального времениWeb
разработанные головоломки, и с традиционнымиHTTP
По сравнению с, имеет много преимуществ:
- Облегченные заголовки сокращают накладные расходы на передачу данных.
- не замужем
Web
Клиенту нужен только одинTCP
соединять. -
WebSocket
Сервер может отправлять данные наWeb
клиент.
Протокол WebSocket относительно прост в реализации. оно используетHTTP
Протокол выполняет начальное рукопожатие. После успешного рукопожатия соединение устанавливается.WebSocket
главное использовать оригиналTCP
Чтение/запись данных.
Запрос клиента выглядит так:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
Вот ответ сервера:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
Как создать приложение WebSocket в Go
На основе встроенного языка Gonet/http
Питание библиотекиWebSocket
сервер, вам нужно:
- инициировать рукопожатие
- Получение фрейма данных от клиента
- Отправить фрейм данных клиенту
- тесное рукопожатие
инициировать рукопожатие
Во-первых, давайте создадимWebSocket
Конечная точкаHTTP
Обработчик:
// HTTP server with WebSocket endpoint
func Server() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
ws, err := NewHandler(w, r)
if err != nil {
// handle error
}
if err = ws.Handshake(); err != nil {
// handle error
}
…
затем инициализируйтеWebSocket
структура.
Первоначальный запрос на рукопожатие всегда исходит от клиента. сервер подтвержденWebSocket
После запроса он должен ответить рукопожатием.
Помните, что вы не можете использоватьhttp.ResponseWriter
Напишите ответ, потому что, как только он начинает отправлять ответ, он закрывает свой базовыйTCP
подключение (этоHTTP
Это определяется механизмом работы протокола, и соединение закрывается после отправки ответа).
Поэтому вам нужно использоватьHTTP
угнать(hijack
). Угоняя, можно завладеть базовымTCP
обработчик соединения иbufio.Writer
. Это позволяет отключитьTCP
Чтение и запись данных при подключении.
// NewHandler initializes a new handler
func NewHandler(w http.ResponseWriter, req *http.Request) (*WS, error) {
hj, ok := w.(http.Hijacker)
if !ok {
// handle error
} .....
}
Для завершения рукопожатия сервер должен ответить соответствующими заголовками.
// Handshake creates a handshake header
func (ws *WS) Handshake() error {
hash := func(key string) string {
h := sha1.New()
h.Write([]byte(key))
h.Write([]byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}(ws.header.Get("Sec-WebSocket-Key"))
.....
}
Инициировано клиентомWebSocket
используется для запросов на подключениеSec-WebSocket-key
Он генерируется случайным образом и кодируется Base64. После принятия запроса серверу необходимо привязать к этому ключу фиксированную строку. Предположим, что секретный ключx3JJHMbDL1EzLkh9GBhXDw==
. В этом примере вы можете использоватьSHA-1
Вычислите двоичное значение и используйтеBase64
закодировать его. получитьHSmrc0sMlYUkAGmm5OPpG2HaGWk=
. затем используйте его какSec-WebSocket-Accept
Значение заголовка ответа.
передать кадр данных
После успешного завершения рукопожатия ваше приложение может считывать данные с клиента или записывать данные на него.Спецификация веб-сокетаОпределяет определенный формат кадра, используемый между клиентом и сервером. Вот битовая структура кадра:
Рисунок: Битовая комбинация передаваемого кадра данныхИспользуйте следующий код для декодирования полезной нагрузки клиента:
// Recv receives data and returns a Frame
func (ws *WS) Recv() (frame Frame, _ error) {
frame = Frame{}
head, err := ws.read(2)
if err != nil {
// handle error
}
Эти строки кода, в свою очередь, позволяют кодировать данные:
// Send sends a Frame
func (ws *WS) Send(fr Frame) error {
// make a slice of bytes of length 2
data := make([]byte, 2)
// Save fragmentation & opcode information in the first byte
data[0] = 0x80 | fr.Opcode
if fr.IsFragment {
data[0] &= 0x7F
}
.....
тесное рукопожатие
Рукопожатие закрывается, когда одна из сторон отправляет кадр закрытия со статусом «закрыто» в качестве полезной нагрузки. При желании сторона, отправляющая кадр закрытия, может отправить причину закрытия в полезной нагрузке. Если закрытие было инициировано клиентом, сервер должен ответить соответствующим кадром закрытия.
// Close sends a close frame and closes the TCP connection
func (ws *Ws) Close() error {
f := Frame{}
f.Opcode = 8
f.Length = 2
f.Payload = make([]byte, 2)
binary.BigEndian.PutUint16(f.Payload, ws.status)
if err := ws.Send(f); err != nil {
return err
}
return ws.conn.Close()
}
Быстро создавайте с помощью сторонних библиотекWebSocket
Служить
Из предыдущих глав видно, чтоGo
автономныйnet/http
реализация библиотекиWebSocket
Служба все еще слишком сложна. К счастью, пар много.WebSocket
Хорошо поддерживаемые сторонние библиотеки могут значительно сократить нашу низкоуровневую работу по написанию кода. Здесь мы используемgorilla web toolkit
Еще одна библиотека для семьиgorilla/websocket
реализовать нашиWebSocket
обслуживание, построение простогоEcho
Служить(echo
Это означает эхо, которое отправляет клиент, а сервер отправляет сообщение обратно клиенту).
мы вhttp_demo
Проектhandler
Создайте новый в каталогеws
подкаталоги для храненияWebSocket
Обработчик запроса, соответствующий маршруту, связанному со службой.
Добавьте два маршрута:
-
/ws/echo
echo
Маршрут для службы WebSocket приложения. -
/ws/echo_display
echo
Маршрут к клиентской странице приложения.
Создайте сервер WebSocket
// handler/ws/echo.go
package ws
import (
"fmt"
"github.com/gorilla/websocket"
"net/http"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func EchoMessage(w http.ResponseWriter, r *http.Request) {
conn, _ := upgrader.Upgrade(w, r, nil) // 实际应用时记得做错误处理
for {
// 读取客户端的消息
msgType, msg, err := conn.ReadMessage()
if err != nil {
return
}
// 把消息打印到标准输出
fmt.Printf("%s sent: %s\n", conn.RemoteAddr(), string(msg))
// 把消息写回客户端,完成回音
if err = conn.WriteMessage(msgType, msg); err != nil {
return
}
}
}
-
conn
Тип переменной*websocket.Conn
,websocket.Conn
тип, используемый для представленияWebSocket
соединять. серверное приложение отHTTP
вызов обработчика запросаUpgrader.Upgrade
способ получить*websocket.Conn
-
вызов подключен
WriteMessage
иReadMessage
способы отправки и получения сообщений. вышеmsg
После его получения он отправляется обратно клиенту ниже.msg
Тип[]byte
.
Создайте клиент WebSocket
Обработчик запроса, соответствующий маршрутизации страницы внешнего интерфейса, выглядит следующим образом и возвращает напрямуюviews/websockets.html
Просто отобразите страницу в браузере.
// handler/ws/echo_display.go
package ws
import "net/http"
func DisplayEcho(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "views/websockets.html")
}
websocket.html
где нам нужно использоватьJavaScript
соединятьWebScoket
Сервис отправляет и принимает сообщения, выложу только из соображений экономии места.JS
Код готов, полный код можно скачать с официального аккаунта через пароль в этом разделе.
<form>
<input id="input" type="text" />
<button onclick="send()">Send</button>
<pre id="output"></pre>
</form>
...
<script>
var input = document.getElementById("input");
var output = document.getElementById("output");
var socket = new WebSocket("ws://localhost:8000/ws/echo");
socket.onopen = function () {
output.innerHTML += "Status: Connected\n";
};
socket.onmessage = function (e) {
output.innerHTML += "Server: " + e.data + "\n";
};
function send() {
socket.send(input.value);
input.value = "";
}
</script>
...
зарегистрировать маршрут
После того, как серверная и клиентская программы готовы, регистрируем маршруты и соответствующие обработчики запросов для них по заранее согласованному пути:
// router/router.go
func RegisterRoutes(r *mux.Router) {
...
wsRouter := r.PathPrefix("/ws").Subrouter()
wsRouter.HandleFunc("/echo", ws.EchoMessage)
wsRouter.HandleFunc("/echo_display", ws.DisplayEcho)
}
Тестовая проверка
Доступ после перезапуска службыhttp://localhost:8000/ws/echo_display
, любое сообщение, введенное в поле ввода, может быть снова отображено в браузере.
Сервер распечатывает полученное сообщение на терминале, а затем вызываетwriteMessage
Сообщение отправляется обратно клиенту, и запись можно просмотреть в терминале.
Суммировать
WebSocket
Он очень широко используется в приложениях, которые сейчас часто обновляются.WebSocket
Программирование также является важным навыком, которым нам необходимо овладеть. Практические упражнения из статьи немного проще, а проверок на ошибки и безопасности нет. В основном, чтобы прояснить общий процесс. оgorilla/websocket
Для получения более подробной информации вам необходимо проверить официальную документацию при его использовании.
Ссылка на ссылку:
Arran Ascension.com/blog/how-to…
woohoo.gorilla toolkit.org/pkg/Web sock…
Предыдущий отзыв
Глубокое погружение в написание HTTP-серверов в Go
Подробное руководство по применению библиотеки шаблонов Go
Создайте статический файловый сервер в Go
Внедрение управления сеансами на стороне клиента с помощью SecureCookie