亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go如何實現(xiàn)Websocket服務以及代理

 更新時間:2025年04月07日 17:00:09   作者:Sakura,.  
這篇文章主要介紹了Go如何實現(xiàn)Websocket服務以及代理方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

Go 實現(xiàn) Websocket服務以及代理

1. 協(xié)議說明

WebSocket 是一種在單個 TCP 連接上進行全雙工通信的協(xié)議。WebSocket 使得客戶端和服務器之間的數(shù)據(jù)交換變得更加簡單,允許服務端主動向客戶端推送數(shù)據(jù)。Websocket 主要用在B/S架構的應用程序中,在 WebSocket API 中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接, 并進行雙向數(shù)據(jù)傳輸。

它的最大特點就是,服務器可以主動向客戶端推送信息,客戶端也可以主動向服務器發(fā)送信息,是真正的雙向平等對話,屬于服務器推送技術的一種。

WebSocket 協(xié)議在2008年誕生,2011 年成為國際標準。現(xiàn)在最新版本瀏覽器都已經支持了。

WebSocket 是一種應用層協(xié)議

WebSocket 的典型特點:

  1. 基于 TCP 協(xié)議的應用層協(xié)議,實現(xiàn)相對簡單
  2. 單個 TCP 連接上進行全雙工通信
  3. 兼容 HTTP 協(xié)議,默認端口也是 80 和 443

ws://host:port/path/querywss://host:port/path/query

  1. 握手階段采用 HTTP 協(xié)議,能通過各種 HTTP 代理服務器
  2. 數(shù)據(jù)格式比較輕量,性能開銷小,通信高效
  3. 可以發(fā)送文本和二進制數(shù)據(jù)
  4. 沒有瀏覽器的同源限制

websocket 的典型場景:

  • 即時通信
  • 協(xié)同編輯/編輯
  • 實時數(shù)據(jù)流的拉取與推送

2. WebSocket 推送和瀏覽器輪詢

在 B/S 開發(fā)領域,若需要瀏覽器 B 即時得到服務器的狀態(tài)更新,常使用兩個方案:

  • 瀏覽器端輪詢
  • 服務器端推送

瀏覽器輪詢:瀏覽器端,當需要獲取最新數(shù)據(jù)狀態(tài)時,利用腳本程序循環(huán)向服務端發(fā)送請求。

服務器推送,服務器端,當狀態(tài)改變時,將數(shù)據(jù)發(fā)送到瀏覽器端。

HTTP/2 版本也支持服務器端推送,但實現(xiàn)上以推送靜態(tài)資源為主,不能基于業(yè)務邏輯推送特定的消息,因此當前的普及使用率 websocket 還是主流。

3. WebSocket 和 http

相同點

  • 應用層協(xié)議
  • B/S 架構中使用
  • 基于 TCP 協(xié)議
  • 端口默認都是:80 和 443

不同點

4. WebSocket 握手過程

通過 HTTP 請求響應,中的頭信息,完成 websocket 握手,如圖:

  • 在請求頭中添加如下信息
# 升級為 websocket
Upgrade: websocket
Connection: Upgrade
# 一個 Base64 encode 的值,有于驗證服務器端是否支持websocket
Sec-WebSocket-Key: x4JJHMbDL22zLk1GBhXDw==
# 用戶協(xié)議,可以視為不同業(yè)務邏輯的頻道
Sec-WebSocket-Protocol: chat
# 協(xié)議版本,13是當前通用版本,幾乎不需要更改
Sec-WebSocket-Version: 13

基于以上請求頭,服務器端,就知道需要將協(xié)議升級為 websocket 協(xié)議,并提供一些驗證信息。

  • 服務端的響應頭
HTTP/1.1 101 Switching Protocols
# 協(xié)議升級
Upgrade: websocket
# 連接狀態(tài)
Connection: Upgrade
# WebSocket服務端根據(jù)Sec-WebSocket-Key生成
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
# WebSocket協(xié)議用戶協(xié)議
Sec-WebSocket-Protocol: chat

基于以上響應頭,瀏覽器端就知道服務器端升級成功,并通過了驗證。

至此,B/S 端可以基于該連接,完成 websocket 雙向通信了。

websocket 只能發(fā)送 GET 請求

5. WebSocket 狀態(tài)碼和消息類型

5.1 狀態(tài)碼

WebSocket協(xié)議狀態(tài)碼解析

5.2 消息類型

TextMessageBinaryMessage 分別表示發(fā)送文本消息和二級制消息

CloseMessage 關閉幀,接收方收到這個消息就關閉連接

PingMessagePongMessage : 是保持心跳的幀

  • 發(fā)送方 -> 接收方是 PingMessage
  • 接收方 -> 發(fā)送方是 PongMessage

由服務器發(fā) ping 給瀏覽器,瀏覽器返回 pong 消息

6. WebSocket 服務器實現(xiàn)

使用 github.com/gorilla/websocket 這個庫函數(shù)

func WebSocketServer() {
	addr := "localhost:8002"
	http.HandleFunc("/wshandler", WebSocketUpgrade)
	log.Println("Starting websocket server at " + addr)

	go func() {
		err := http.ListenAndServe(addr, nil)
		if err != nil {
			log.Fatal(err)
		}
	}()

	log.Println("WebSocket 服務器正在運行。按Ctrl+C退出")
	select {}
}

func WebSocketUpgrade(resp http.ResponseWriter, req *http.Request) {
	// 初始化 Upgrader
	upgrader := websocket.Upgrader{} // 使用默認的選項
	// 第三個參數(shù)是響應頭,默認會初始化
	conn, err := upgrader.Upgrade(resp, req, nil)
	if err != nil {
		log.Println(err)
		return
	}
	defer conn.Close()

	// 讀取客戶端的發(fā)送額消息,并返回
	go ReadMessage(conn)
	select {}
}

// 讀取客戶端發(fā)送的消息,并返回
func ReadMessage(conn *websocket.Conn) {
	for {
		// 消息類型:文本消息和二進制消息
		messageType, msg, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			return
		}
		fmt.Println("receive msg:", string(msg))

		err = conn.WriteMessage(messageType, msg)
		if err != nil {
			log.Println("write error:", err)
			return
		}
	}
}

使用 Apifox 測試 websocket 是否能連接并且發(fā)送消息

消息發(fā)送成功,同時也接收到來服務端的消息

消息接收成功

7. WebSocket 代理實現(xiàn)

package websocket

import (
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
)

var (
	// 代理服務器地址
	proxyServer     = "127.0.0.1:8082"
	// 真實websocket服務器地址
	websocketServer = "http://127.0.0.1:8002"
)

func WebSocketProxy() {
	url, err := url.Parse(websocketServer)
	if err != nil {
		log.Println(err)
	}
	proxy := httputil.NewSingleHostReverseProxy(url)
	log.Println("WebSocket 代理啟動, 按CTRL+C退出")
	http.ListenAndServe(proxyServer, proxy)
}

8. WebSocket 服務端主動推送功能的實現(xiàn)

websocket 服務器每隔 3 秒會主動向服務器推送消息"Heart Beat"

func WebSocketServer() {
	addr := "localhost:8002"
	http.HandleFunc("/wshandler", WebSocketUpgrade)
	log.Println("Starting websocket server at " + addr)

	go func() {
		err := http.ListenAndServe(addr, nil)
		if err != nil {
			log.Fatal(err)
		}
	}()

	log.Println("WebSocket 服務器正在運行。按Ctrl+C退出")
	select {}
}

func WebSocketUpgrade(resp http.ResponseWriter, req *http.Request) {
	// 初始化 Upgrader
	upgrader := websocket.Upgrader{} // 使用默認的選項
	// 第三個參數(shù)是響應頭,默認會初始化
	conn, err := upgrader.Upgrade(resp, req, nil)
	if err != nil {
		log.Println(err)
		return
	}
	defer conn.Close()

	// 主動向服務端推送消息
	go PushMessage(conn)

	// 讀取客戶端的發(fā)送額消息,并返回
	go ReadMessage(conn)
	select {}
}

// websocket 服務器主動服務器推送消息
func PushMessage(conn *websocket.Conn) {
	for {
		err := conn.WriteMessage(websocket.TextMessage, []byte("heart beat"))
		if err != nil {
			log.Println(err)
			return
		}
		time.Sleep(time.Second * 3)
	}
}

// 讀取客戶端發(fā)送的消息,并返回
func ReadMessage(conn *websocket.Conn) {
	for {
		// 消息類型:文本消息和二進制消息
		messageType, msg, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			return
		}
		fmt.Println("receive msg:", string(msg))

		err = conn.WriteMessage(messageType, msg)
		if err != nil {
			log.Println("write error:", err)
			return
		}
	}
}

每隔三秒可以看到服務推送過來的消息

總結

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Go使用proto3的踩坑實戰(zhàn)記錄

    Go使用proto3的踩坑實戰(zhàn)記錄

    這篇文章主要給大家介紹了關于Go使用proto3的踩坑記錄,文中通過實例代碼介紹的非常詳細,對大家學習或者會用Go語言具有一定的參考學習價值,需要的朋友可以參考下
    2023-02-02
  • Go 語言 JSON 標準庫的使用

    Go 語言 JSON 標準庫的使用

    今天通過本文給大家介紹Go 語言 JSON 標準庫的使用小結,包括序列化和反序列化的相關知識,感興趣的朋友跟隨小編一起看看吧
    2021-10-10
  • Go?常見設計模式之單例模式詳解

    Go?常見設計模式之單例模式詳解

    單例模式是設計模式中最簡單的一種模式,單例模式能夠確保無論對象被實例化多少次,全局都只有一個實例存在,在Go?語言有多種方式可以實現(xiàn)單例模式,所以我們今天就來一起學習下吧
    2023-07-07
  • 從源碼解析golang Timer定時器體系

    從源碼解析golang Timer定時器體系

    本文詳細介紹了Go語言中的Timer和Ticker的使用方式、錯誤使用方式以及底層源碼實現(xiàn),Timer是一次性的定時器,而Ticker是循環(huán)定時器,正確使用時需要注意返回的channel和垃圾回收問題,Go 1.23版本對定時器進行了改進,優(yōu)化了垃圾回收和停止、重置相關方法
    2025-01-01
  • golang fmt格式“占位符”的實例用法詳解

    golang fmt格式“占位符”的實例用法詳解

    在本篇文章里小編給大家整理的是一篇關于golang fmt格式“占位符”的實例用法詳解內容,有興趣的朋友們可以學習下。
    2021-07-07
  • golang?基于?mysql?簡單實現(xiàn)分布式讀寫鎖

    golang?基于?mysql?簡單實現(xiàn)分布式讀寫鎖

    這篇文章主要介紹了golang?基于mysql簡單實現(xiàn)分布式讀寫鎖,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • GO語言中的常量

    GO語言中的常量

    go語言支持的常量有字符型,字符串型,布爾型和數(shù)字型。本文實例講述了Go語言中常量定義方法。分享給大家供大家參考。
    2015-04-04
  • Go批量操作excel導入到mongodb的技巧

    Go批量操作excel導入到mongodb的技巧

    這篇文章主要介紹了Go批量操作excel導入到mongo,包括選擇命令行包,讀取配置連接數(shù)據(jù)庫的方法,本文示例代碼相結合給大家介紹的非常詳細,需要的朋友可以參考下
    2022-03-03
  • Go-RESTful實現(xiàn)下載功能思路詳解

    Go-RESTful實現(xiàn)下載功能思路詳解

    這篇文章主要介紹了Go-RESTful實現(xiàn)下載功能,文件下載包括文件系統(tǒng)IO和網絡IO,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-10-10
  • go中Excelize處理excel表實現(xiàn)帶數(shù)據(jù)校驗的文件導出

    go中Excelize處理excel表實現(xiàn)帶數(shù)據(jù)校驗的文件導出

    本文主要介紹了go中Excelize處理excel表實現(xiàn)帶數(shù)據(jù)校驗的文件導出,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06

最新評論