欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

Go 實(shí)現(xiàn) Websocket服務(wù)以及代理

1. 協(xié)議說(shuō)明

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

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

WebSocket 協(xié)議在2008年誕生,2011 年成為國(guó)際標(biāo)準(zhǔn)?,F(xiàn)在最新版本瀏覽器都已經(jīng)支持了。

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

WebSocket 的典型特點(diǎn):

  1. 基于 TCP 協(xié)議的應(yīng)用層協(xié)議,實(shí)現(xiàn)相對(duì)簡(jiǎn)單
  2. 單個(gè) TCP 連接上進(jìn)行全雙工通信
  3. 兼容 HTTP 協(xié)議,默認(rèn)端口也是 80 和 443

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

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

websocket 的典型場(chǎng)景:

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

2. WebSocket 推送和瀏覽器輪詢

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

  • 瀏覽器端輪詢
  • 服務(wù)器端推送

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

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

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

3. WebSocket 和 http

相同點(diǎn)

  • 應(yīng)用層協(xié)議
  • B/S 架構(gòu)中使用
  • 基于 TCP 協(xié)議
  • 端口默認(rèn)都是:80 和 443

不同點(diǎn)

4. WebSocket 握手過(guò)程

通過(guò) HTTP 請(qǐng)求響應(yīng),中的頭信息,完成 websocket 握手,如圖:

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

基于以上請(qǐng)求頭,服務(wù)器端,就知道需要將協(xié)議升級(jí)為 websocket 協(xié)議,并提供一些驗(yàn)證信息。

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

基于以上響應(yīng)頭,瀏覽器端就知道服務(wù)器端升級(jí)成功,并通過(guò)了驗(yàn)證。

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

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

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

5.1 狀態(tài)碼

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

5.2 消息類(lèi)型

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

CloseMessage 關(guān)閉幀,接收方收到這個(gè)消息就關(guān)閉連接

PingMessagePongMessage : 是保持心跳的幀

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

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

6. WebSocket 服務(wù)器實(shí)現(xiàn)

使用 github.com/gorilla/websocket 這個(gè)庫(kù)函數(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 服務(wù)器正在運(yùn)行。按Ctrl+C退出")
	select {}
}

func WebSocketUpgrade(resp http.ResponseWriter, req *http.Request) {
	// 初始化 Upgrader
	upgrader := websocket.Upgrader{} // 使用默認(rèn)的選項(xiàng)
	// 第三個(gè)參數(shù)是響應(yīng)頭,默認(rèn)會(huì)初始化
	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 {
		// 消息類(lèi)型:文本消息和二進(jìn)制消息
		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 測(cè)試 websocket 是否能連接并且發(fā)送消息

消息發(fā)送成功,同時(shí)也接收到來(lái)服務(wù)端的消息

消息接收成功

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

package websocket

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

var (
	// 代理服務(wù)器地址
	proxyServer     = "127.0.0.1:8082"
	// 真實(shí)websocket服務(wù)器地址
	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 代理啟動(dòng), 按CTRL+C退出")
	http.ListenAndServe(proxyServer, proxy)
}

8. WebSocket 服務(wù)端主動(dòng)推送功能的實(shí)現(xiàn)

websocket 服務(wù)器每隔 3 秒會(huì)主動(dòng)向服務(wù)器推送消息"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 服務(wù)器正在運(yùn)行。按Ctrl+C退出")
	select {}
}

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

	// 主動(dòng)向服務(wù)端推送消息
	go PushMessage(conn)

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

// websocket 服務(wù)器主動(dòng)服務(wù)器推送消息
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 {
		// 消息類(lèi)型:文本消息和二進(jìn)制消息
		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
		}
	}
}

每隔三秒可以看到服務(wù)推送過(guò)來(lái)的消息

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

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

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

    這篇文章主要給大家介紹了關(guān)于Go使用proto3的踩坑記錄,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者會(huì)用Go語(yǔ)言具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-02-02
  • Go 語(yǔ)言 JSON 標(biāo)準(zhǔn)庫(kù)的使用

    Go 語(yǔ)言 JSON 標(biāo)準(zhǔn)庫(kù)的使用

    今天通過(guò)本文給大家介紹Go 語(yǔ)言 JSON 標(biāo)準(zhǔn)庫(kù)的使用小結(jié),包括序列化和反序列化的相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧
    2021-10-10
  • Go?常見(jiàn)設(shè)計(jì)模式之單例模式詳解

    Go?常見(jiàn)設(shè)計(jì)模式之單例模式詳解

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

    從源碼解析golang Timer定時(shí)器體系

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

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

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

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

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

    GO語(yǔ)言中的常量

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

    Go批量操作excel導(dǎo)入到mongodb的技巧

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

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

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

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

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

最新評(píng)論