Публичный аккаунт WeChat "Advanced Architect", подписывайтесь, читайте, комментируйте, лайкайте!!!!
предисловие
Шум дождя, сопровождаемый звуком машины за окном. В своем сердце подумайте о своих мечтах и мыслях.
Сегодня поговорим об использовании Websocket в GoLang. Точно так же, когда мы изучаем Java Websocket, нам может понадобиться тщательный процесс обучения. Сегодня давайте очистим наши умы,
Научитесь идти!
WebSocket
Прежде всего, давайте узнаем, что, черт возьми, такое WebSocket. Ниже приводится выдержка из энциклопедии Baidu.
WebSocketявляется единственнымTCPна связиполный дуплекспротокол связи. Протокол связи WebSocket был принят в 2011 году.IETFОпределен как стандартный RFC 6455 и дополнен RFC7936. Веб-сокетAPIтакже былW3Cустановить стандартно.
WebSocket упрощает обмен данными между клиентом и сервером, позволяя серверу активно передавать данные клиенту. В API WebSocket браузеру и серверу нужно выполнить только одно рукопожатие, и между ними может быть создано постоянное соединение, и может выполняться двусторонняя передача данных.
Gorilla Websocket
Функция для написания клиента/сервера websocket в Go, использование в GoLangGorilla Websocketупаковка. Основной код репозитория находится по адресуна Гитхабе.
Теперь давайте посмотрим, как быстро настроить тестируемое приложение Websocket с Gorilla.
Установите пакет Gorilla Websocket Go
Нет никаких зависимостей, кроме работающего компилятора Go, поэтому вам просто нужно использоватьgo get
!
go get github.com/gorilla/websocket
Дизайн веб-сокета
Прежде чем приступить к каким-либо примерам, давайте сначала разработаем примерный план того, что нужно сделать.
Любое приложение, использующее протокол websocket, обычно требуетклиентисервер.
Серверная программа привязывается к порту на сервере и начинает прослушивать любые соединения Websocket. Детали, связанные с подключением, определяются протоколом веб-сокета, который работает через необработанные HTTP-соединения.
Клиентская программа пытается установить соединение с сервером, используя URL-адрес веб-сокета. Обратите внимание, что хотя Gorilla предоставляет нам API для написания клиентов, нет необходимости использовать Golang для реализации клиентских программ.
Если ваше веб-приложение использует отдельный интерфейс, обычно клиент Websocket будет реализован на этом языке (Javascript и т. д.).
Однако для целей описания мы будем писать клиентские и серверные программы одновременно на Go.
Теперь давайте запустим нашу клиент-серверную архитектуру!
мы будемserver.go
сервер иclient.go
Клиент предоставляет программу.
Использование веб-сокетов Gorilla — создайте наш сервер
Этот веб-сервер будет реализован на обычном http-сервере. мы будемnet/http
Используется для обслуживания необработанных HTTP-соединений.
Сейчас вserver.go
, давайте напишем обычный HTTP-сервер и добавимsocketHandler()
Функция для обработки логики веб-сокетов.
// server.go
package main
import (
"log"
"net/http"
"time"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{} // use default options
func socketHandler(w http.ResponseWriter, r *http.Request) {
// Upgrade our raw HTTP connection to a websocket based one
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("Error during connection upgradation:", err)
return
}
defer conn.Close()
// The event loop
for {
messageType, message, err := conn.ReadMessage()
if err != nil {
log.Println("Error during message reading:", err)
break
}
log.Printf("Received: %s", message)
err = conn.WriteMessage(messageType, message)
if err != nil {
log.Println("Error during message writing:", err)
break
}
}
}
func home(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Index Page")
}
func main() {
http.HandleFunc("/socket", socketHandler)
http.HandleFunc("/", home)
log.Fatal(http.ListenAndServe("localhost:8080", nil))
}
Работа Gorilla заключается в преобразовании необработанного HTTP-соединения в соединение с веб-сокетом с отслеживанием состояния.
Вот почему используйтеstruct
перечислитьUpgrader
Приходите и помогите нам, почему.
Мы используем глобальную переменную обновления, чтобы помочь нам преобразовать любое входящее HTTP-соединение в протокол веб-сокета.upgrader.Upgrade()
. Это вернет нам*websocket.Connection
, который мы теперь можем использовать для обработки соединений через веб-сокеты.
Сервер читает сообщение, используяconn.ReadMessage()
написать сообщениеconn.WriteMessage()
Сервер просто повторяет все входящие сообщения Websocket клиенту, так что это объясняет, как использовать Websocket дляполный дуплекскоммуникация.
Теперь перейдем к клиентской реализацииclient.go
.
Создадим нашу клиентскую программу
Мы также будем использовать Gorilla для написания клиента. Этот простой клиент будет отправлять сообщения каждую секунду. Если вся наша система работает должным образом, сервер будет получать пакеты с интервалом в 1 секунду и отвечать тем же сообщением.
Клиент также будет иметь возможность получать входящие пакеты Websocket. В нашей программе у нас будет отдельный обработчик горутиныreceiveHandler
, который прослушивает входящие пакеты.
// client.go
package main
import (
"log"
"os"
"os/signal"
"time"
"github.com/gorilla/websocket"
)
var done chan interface{}
var interrupt chan os.Signal
func receiveHandler(connection *websocket.Conn) {
defer close(done)
for {
_, msg, err := connection.ReadMessage()
if err != nil {
log.Println("Error in receive:", err)
return
}
log.Printf("Received: %s\n", msg)
}
}
func main() {
done = make(chan interface{}) // Channel to indicate that the receiverHandler is done
interrupt = make(chan os.Signal) // Channel to listen for interrupt signal to terminate gracefully
signal.Notify(interrupt, os.Interrupt) // Notify the interrupt channel for SIGINT
socketUrl := "ws://localhost:8080" + "/socket"
conn, _, err := websocket.DefaultDialer.Dial(socketUrl, nil)
if err != nil {
log.Fatal("Error connecting to Websocket Server:", err)
}
defer conn.Close()
go receiveHandler(conn)
// Our main loop for the client
// We send our relevant packets here
for {
select {
case <-time.After(time.Duration(1) * time.Millisecond * 1000):
// Send an echo packet every second
err := conn.WriteMessage(websocket.TextMessage, []byte("Hello from GolangDocs!"))
if err != nil {
log.Println("Error during writing to websocket:", err)
return
}
case <-interrupt:
// We received a SIGINT (Ctrl + C). Terminate gracefully...
log.Println("Received SIGINT interrupt signal. Closing all pending connections")
// Close our websocket connection
err := conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("Error during closing websocket:", err)
return
}
select {
case <-done:
log.Println("Receiver Channel Closed! Exiting....")
case <-time.After(time.Duration(1) * time.Second):
log.Println("Timeout in closing receiving channel. Exiting....")
}
return
}
Если вы посмотрите на код, то увидите, что я создаю два каналаdone
,interrupt
используется дляreceiveHandler()
и связь междуmain()
.
Мы используем select в бесконечном цикле для прослушивания событий через канал. мыconn.WriteMessage()
Пишите сообщения каждую секунду. Если активируется сигнал прерывания, все ожидающие соединения закрываются, и мы можем выйти корректно!
вложенныйselect
заключается в обеспечении двух вещей:
- если
receiveHandler
выход канала, канал'done'
закроется. Это первыйcase <-done
состояние - если
'done'
Канал не закрыт, будет тайм-аут через 1 секунду, поэтому программа завершится через 1-секундный тайм-аут
Тщательно обрабатывайте все дела, используя каналыselect
, у вас может быть минимальная архитектура, которую можно легко расширить.
Наконец, давайте посмотрим, что мы получим при одновременном запуске клиента и сервера!
вывод
Суммировать
Обучение — это постоянная вещь, сегодня мы узнали, как использовать Websocket.
Давайте, товарищи, продолжайте работать! !