golang開發(fā)?gorilla?websocket的使用示例詳解
很多APP都需要主動(dòng)向用戶推送消息,這就需要用到長(zhǎng)連接的服務(wù),即我們通常提到的websocket,同樣也是使用socket服務(wù),通信協(xié)議是基本類似的,在go中用的最多的、也是最簡(jiǎn)單的socket服務(wù)就是gorilla/websocket,它有21.1K的star,足以說明它的受歡迎程度, 它的github地址是 https://github.com/gorilla/websocket,我們的長(zhǎng)連接服務(wù)也是通過gorilla/websocket改造出來的。
websocket的簡(jiǎn)單使用
我們使用的版本是1.3.0,首先下載websocket
go get github.com/gorilla/websocket@v1.3.0
把websocket/examples/echo下面的 client.go server.go 現(xiàn)在下來拷貝到項(xiàng)目里面。
https://github.com/gorilla/websocket/blob/v1.3.0/examples/echo/server.go
https://github.com/gorilla/websocket/blob/v1.3.0/examples/echo/client.go
在一個(gè)終端執(zhí)行 websocket 服務(wù)
go run server.go
recv: 2024-04-16 15:09:45.805438 +0800 CST m=+1.007536889 recv: 2024-04-16 15:09:46.805425 +0800 CST m=+2.007517605 recv: 2024-04-16 15:09:47.806274 +0800 CST m=+3.008359325 recv: 2024-04-16 15:09:48.80495 +0800 CST m=+4.007028866 recv: 2024-04-16 15:09:49.805743 +0800 CST m=+5.007816108 recv: 2024-04-16 15:09:50.806087 +0800 CST m=+6.008153310 recv: 2024-04-16 15:09:51.805348 +0800 CST m=+7.007407266
再打開一個(gè)終端執(zhí)行 go run client.go,充當(dāng)客戶端
connecting to ws://localhost:8080/echo recv: 2024-04-16 15:09:45.805438 +0800 CST m=+1.007536889 recv: 2024-04-16 15:09:46.805425 +0800 CST m=+2.007517605 recv: 2024-04-16 15:09:47.806274 +0800 CST m=+3.008359325 recv: 2024-04-16 15:09:48.80495 +0800 CST m=+4.007028866 recv: 2024-04-16 15:09:49.805743 +0800 CST m=+5.007816108 recv: 2024-04-16 15:09:50.806087 +0800 CST m=+6.008153310 recv: 2024-04-16 15:09:51.805348 +0800 CST m=+7.007407266
我們看看這個(gè)簡(jiǎn)單的例子。
client.go
go func() {
defer close(done)
for {
_, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
return
}
log.Printf("recv: %s", message)
}
}()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-done:
return
case t := <-ticker.C:
err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
if err != nil {
log.Println("write:", err)
return
}
case <-interrupt:
log.Println("interrupt")
// Cleanly close the connection by sending a close message and then
// waiting (with timeout) for the server to close the connection.
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("write close:", err)
return
}
select {
case <-done:
case <-time.After(time.Second):
}
return
}
}go func() 的 c.ReadMessage 不停的從socket里面讀取數(shù)據(jù)并且打印。
for 循環(huán)不停的從1秒的定時(shí)器里面讀取時(shí)間,寫到socket
server.go
for {
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Printf("recv: %s", message)
err = c.WriteMessage(mt, message)
if err != nil {
log.Println("write:", err)
break
}
}for c.ReadMessage 循環(huán)不停的從 socket讀取數(shù)據(jù),把數(shù)據(jù)打印之后,又寫給客戶端。
這是大致的websocket 客戶端與服務(wù)端通信的簡(jiǎn)單例子。
改成自定義的協(xié)議
我們使用二進(jìn)制數(shù)據(jù)流,自定義的協(xié)議是這樣的,
先是無符號(hào)的 uint 占4個(gè)字節(jié),表示行為邏輯,比如111-獲取信息, 110- 加好友等等
后面是具體的數(shù)據(jù),跟HTTP請(qǐng)求的GET或者POST參數(shù)類似,具體數(shù)據(jù)格式定義好就行,比如可以使用JSON數(shù)據(jù)、可以使用RPC定義好的數(shù)據(jù)格式
修改完之后 client.go 代碼是這樣的
for {
select {
case <-done:
return
case <-ticker.C:
buf := bytes.NewBuffer([]byte{})
binary.Write(buf, binary.BigEndian, uint32(110))
binary.Write(buf, binary.BigEndian, []byte("我們都好"))
err := c.WriteMessage(websocket.BinaryMessage, buf.Bytes())
if err != nil {
log.Println("write:", err)
return
}
case <-interrupt:
log.Println("interrupt")
// Cleanly close the connection by sending a close message and then
// waiting (with timeout) for the server to close the connection.
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("write close:", err)
return
}
select {
case <-done:
case <-time.After(time.Second):
}
return
}
}主要是這個(gè)
buf := bytes.NewBuffer([]byte{})
binary.Write(buf, binary.BigEndian, uint32(110))
binary.Write(buf, binary.BigEndian, []byte("我們都好"))創(chuàng)建一個(gè)bytes Buffer
寫入一個(gè)uint32,占4個(gè)字節(jié),表示行為邏輯
寫入行為邏輯具體的數(shù)據(jù)
以上采用大端通信
修改之后的 server.go
for {
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Println("messagetype:%d", mt)
log.Println("messagelen:%d", len(message))
log.Println("messagetype:%d", binary.BigEndian.Uint32(message[0:4]))
log.Println("recv: %s", string(message[4:]))
err = c.WriteMessage(mt, message)
if err != nil {
log.Println("write:", err)
break
}
}mt websocket 類型
TextMessage = 1 文本類型傳傳輸
BinaryMessage = 2 字節(jié)類型傳輸
從socket里面獲取到message之后
先取前4個(gè)字節(jié),表示邏輯行為
再取剩余的字節(jié),表示行為邏輯需要的參數(shù)
我們重新執(zhí)行一下,server.go 和 client.go
go run client.go connecting to ws://localhost:8080/echo recv: n我們都好 recv: n我們都好 go run server.go messagetype:%d 2 messagelen:%d 16 messagetype:%d 110 recv: %s 我們都好
messagetype=2表示二進(jìn)制通信
message長(zhǎng)度是16,前四個(gè)字節(jié)是無符號(hào)整形,四個(gè)漢字占12個(gè)字節(jié),一共16個(gè)字節(jié),無符號(hào)uint是110表示加好友。
這就是一個(gè)簡(jiǎn)單自定義協(xié)議的socket服務(wù)。
如果有需要登錄鑒權(quán)的話,在server.go中可以從r *http.Request 獲取header或者cookie,進(jìn)行登錄鑒權(quán)驗(yàn)證。
生產(chǎn)的部署
因?yàn)槭?websocket 協(xié)議,如果有代理服務(wù)器的話,需要在各代理服務(wù)器上的Nginx做協(xié)議升級(jí),將HTTP 升級(jí)為 websocket ,比如下面的代理服務(wù)器。
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
location /serv/ {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_connect_timeout 3;
proxy_redirect off;
proxy_read_timeout 3600;
proxy_send_timeout 3600;
proxy_pass http://push_web/serv/;
}
}到此這篇關(guān)于golang開發(fā) gorilla websocket的使用示例詳解的文章就介紹到這了,更多相關(guān)golang開發(fā) gorilla websocket內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語言實(shí)現(xiàn)的可讀性更高的并發(fā)神庫詳解
這篇文章主要為大家介紹了Go語言實(shí)現(xiàn)的可讀性更高的并發(fā)神庫詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
golang利用redis和gin實(shí)現(xiàn)保存登錄狀態(tài)校驗(yàn)登錄功能
這篇文章主要介紹了golang利用redis和gin實(shí)現(xiàn)保存登錄狀態(tài)校驗(yàn)登錄功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01
Go實(shí)現(xiàn)替換(覆蓋)文件某一行內(nèi)容的示例代碼
本文主要介紹了Go實(shí)現(xiàn)替換(覆蓋)文件某一行內(nèi)容的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
基于Go+OpenCV實(shí)現(xiàn)人臉識(shí)別功能的詳細(xì)示例
OpenCV是一個(gè)強(qiáng)大的計(jì)算機(jī)視覺庫,提供了豐富的圖像處理和計(jì)算機(jī)視覺算法,本文將向你介紹在Mac上安裝OpenCV的步驟,并演示如何使用Go的OpenCV綁定庫進(jìn)行人臉識(shí)別,需要的朋友可以參考下2023-07-07
Golang中基礎(chǔ)的命令行模塊urfave/cli的用法說明
這篇文章主要介紹了Golang中基礎(chǔ)的命令行模塊urfave/cli的用法說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12
詳解Golang中Context的三個(gè)常見應(yīng)用場(chǎng)景
Golang?context主要用于定義超時(shí)取消,取消后續(xù)操作,在不同操作中傳遞值。本文通過簡(jiǎn)單易懂的示例進(jìn)行說明,感興趣的可以了解一下2022-12-12
Go條件控制語句詳解(if-else、switch和select)
條件語句用于檢查一個(gè)條件是否為真,并根據(jù)條件的真假來決定是否執(zhí)行相應(yīng)的代碼,下面這篇文章主要給大家介紹了關(guān)于Go條件控制語句(if-else、switch和select)的相關(guān)資料,需要的朋友可以參考下2024-03-03

