国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

腳本之家,腳本語言編程技術(shù)及教程分享平臺!
分類導(dǎo)航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務(wù)器之家 - 腳本之家 - Golang - 使用Go語言創(chuàng)建WebSocket服務(wù)的實(shí)現(xiàn)示例

使用Go語言創(chuàng)建WebSocket服務(wù)的實(shí)現(xiàn)示例

2020-06-07 12:02kevinyan Golang

這篇文章主要介紹了使用Go語言創(chuàng)建WebSocket服務(wù)的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

今天介紹如何用 Go 語言創(chuàng)建 WebSocket 服務(wù),文章的前兩部分簡要介紹了 WebSocket 協(xié)議以及用 Go 標(biāo)準(zhǔn)庫如何創(chuàng)建 WebSocket 服務(wù)。第三部分實(shí)踐環(huán)節(jié)我們使用了 gorilla/websocket 庫幫助我們快速構(gòu)建 WebSocket 服務(wù),它幫封裝了使用 Go 標(biāo)準(zhǔn)庫實(shí)現(xiàn) WebSocket 服務(wù)相關(guān)的基礎(chǔ)邏輯,讓我們能從繁瑣的底層代碼中解脫出來,根據(jù)業(yè)務(wù)需求快速構(gòu)建 WebSocket 服務(wù)。

Go Web 編程系列的每篇文章的源代碼都打了對應(yīng)版本的軟件包,供大家參考。公眾號中回復(fù) gohttp10 獲取本文源代碼

WebSocket介紹

WebSocket 通信協(xié)議通過單個(gè) TCP 連接提供全雙工通信通道。與 HTTP 相比, WebSocket 不需要你為了獲得響應(yīng)而發(fā)送請求。它允許雙向數(shù)據(jù)流,因此您只需等待服務(wù)器發(fā)送的消息即可。當(dāng) Websocket 可用時(shí),它將向您發(fā)送一條消息。 對于需要連續(xù)數(shù)據(jù)交換的服務(wù)(例如即時(shí)通訊程序,在線游戲和實(shí)時(shí)交易系統(tǒng)), WebSocket 是一個(gè)很好的解決方案。 WebSocket 連接由瀏覽器請求,并由服務(wù)器響應(yīng),然后建立連接,此過程通常稱為握手。 WebSocket 中的特殊標(biāo)頭僅需要瀏覽器與服務(wù)器之間的一次握手即可建立連接,該連接將在其整個(gè)生命周期內(nèi)保持活動狀態(tài)。 WebSocket 解決了許多實(shí)時(shí) Web 開發(fā)的難題,并且與傳統(tǒng)的 HTTP 相比,具有許多優(yōu)點(diǎn):

  1. 輕量級報(bào)頭減少了數(shù)據(jù)傳輸開銷。
  2. 單個(gè)Web客戶端僅需要一個(gè)TCP連接。
  3. WebSocket服務(wù)器可以將數(shù)據(jù)推送到Web客戶端。

WebSocket協(xié)議實(shí)現(xiàn)起來相對簡單。它使用 HTTP 協(xié)議進(jìn)行初始握手。握手成功后即建立連接, WebSocket 實(shí)質(zhì)上使用原始 TCP 讀取/寫入數(shù)據(jù)。

使用Go語言創(chuàng)建WebSocket服務(wù)的實(shí)現(xiàn)示例

客戶端請求如下所示:

?
1
2
3
4
5
6
7
8
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

這是服務(wù)器響應(yīng):

?
1
2
3
4
5
HTTP/1.1 101 Switching Protocols
 Upgrade: websocket
 Connection: Upgrade
 Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
 Sec-WebSocket-Protocol: chat

如何在Go中創(chuàng)建WebSocket應(yīng)用

要基于Go 語言內(nèi)置的 net/http 庫編寫 WebSocket 服務(wù)器,你需要:

  • 發(fā)起握手
  • 從客戶端接收數(shù)據(jù)幀
  • 發(fā)送數(shù)據(jù)幀給客戶端
  • 關(guān)閉握手

發(fā)起握手

首先,讓我們創(chuàng)建一個(gè)帶有 WebSocket 端點(diǎn)的 HTTP 處理程序:

?
1
2
3
4
5
6
7
8
9
10
11
// 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 結(jié)構(gòu)。

初始握手請求始終來自客戶端。服務(wù)器確定了 WebSocket 請求后,需要使用握手響應(yīng)進(jìn)行回復(fù)。

請記住,你無法使用 http.ResponseWriter 編寫響應(yīng),因?yàn)橐坏╅_始發(fā)送響應(yīng),它將關(guān)閉其基礎(chǔ)的 TCP 連接(這是 HTTP 協(xié)議的運(yùn)行機(jī)制決定的,發(fā)送響應(yīng)后即關(guān)閉連接)。

因此,您需要使用 HTTP 劫持( hijack )。通過劫持,可以接管基礎(chǔ)的 TCP 連接處理程序和 bufio.Writer 。這使可以在不關(guān)閉 TCP 連接的情況下讀取和寫入數(shù)據(jù)。

?
1
2
3
4
5
6
7
// NewHandler initializes a new handler
func NewHandler(w http.ResponseWriter, req *http.Request) (*WS, error) {
  hj, ok := w.(http.Hijacker)
  if !ok {
   // handle error
  }     .....
}

要完成握手,服務(wù)器必須使用適當(dāng)?shù)念^進(jìn)行響應(yīng)。

?
1
2
3
4
5
6
7
8
9
10
11
12
// 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"))
  .....
}

客戶端發(fā)起 WebSocket 連接請求時(shí)用的 Sec-WebSocket-key 是隨機(jī)生成的,并且是Base64編碼的。接受請求后,服務(wù)器需要將此密鑰附加到固定字符串。假設(shè)秘鑰是 x3JJHMbDL1EzLkh9GBhXDw== 。在這個(gè)例子中,可以使用 SHA-1 計(jì)算二進(jìn)制值,并使用 Base64 對其進(jìn)行編碼。得到 HSmrc0sMlYUkAGmm5OPpG2HaGWk= 。然后使用它作為 Sec-WebSocket-Accept 響應(yīng)頭的值。

傳輸數(shù)據(jù)幀

握手成功完成后,您的應(yīng)用程序可以從客戶端讀取數(shù)據(jù)或向客戶端寫入數(shù)據(jù)。WebSocket規(guī)范 定義了的一個(gè)客戶機(jī)和服務(wù)器之間使用的特定幀格式。這是框架的位模式:

使用Go語言創(chuàng)建WebSocket服務(wù)的實(shí)現(xiàn)示例

圖:傳輸數(shù)據(jù)幀的位模式

使用以下代碼對客戶端有效負(fù)載進(jìn)行解碼:

?
1
2
3
4
5
6
7
// 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
  }

反過來,這些代碼行允許對數(shù)據(jù)進(jìn)行編碼:

?
1
2
3
4
5
6
7
8
9
10
11
// 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
  }
  .....

關(guān)閉握手

當(dāng)各方之一發(fā)送狀態(tài)為關(guān)閉的關(guān)閉幀作為有效負(fù)載時(shí),握手將關(guān)閉。可選的,發(fā)送關(guān)閉幀的一方可以在有效載荷中發(fā)送關(guān)閉原因。如果關(guān)閉是由客戶端發(fā)起的,則服務(wù)器應(yīng)發(fā)送相應(yīng)的關(guān)閉幀作為響應(yīng)。

?
1
2
3
4
5
6
7
8
9
10
11
12
// 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()
}

使用第三方庫快速構(gòu)建WebSocket服務(wù)

通過上面的章節(jié)可以看到用 Go 自帶的 net/http 庫實(shí)現(xiàn) WebSocket 服務(wù)還是太復(fù)雜了。好在有很多對 WebSocket 支持良好的第三方庫,能減少我們很多底層的編碼工作。這里我們使用 gorilla web toolkit 家族的另外一個(gè)庫 gorilla/websocket 來實(shí)現(xiàn)我們的 WebSocket 服務(wù),構(gòu)建一個(gè)簡單的 Echo 服務(wù)( echo 意思是回音,就是客戶端發(fā)什么,服務(wù)端再把消息發(fā)回給客戶端)。

我們在 http_demo 項(xiàng)目的 handler 目錄下新建一個(gè) ws 子目錄用來存放 WebSocket 服務(wù)相關(guān)的路由對應(yīng)的請求處理程序。

增加兩個(gè)路由:

  • /ws/echo echo 應(yīng)用的WebSocket 服務(wù)的路由
  • /ws/echo_display echo 應(yīng)用的客戶端頁面的路由。 創(chuàng)建WebSocket服務(wù)端
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 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) // 實(shí)際應(yīng)用時(shí)記得做錯(cuò)誤處理
 
    for {
        // 讀取客戶端的消息
        msgType, msg, err := conn.ReadMessage()
        if err != nil {
            return
        }
 
        // 把消息打印到標(biāo)準(zhǔn)輸出
        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 連接。服務(wù)器應(yīng)用程序從 HTTP 請求處理程序調(diào)用 Upgrader.Upgrade 方法以獲取 *websocket.Conn
  • 調(diào)用連接的 WriteMessageReadMessage 方法發(fā)送和接收消息。上面的 msg 接收到后在下面又回傳給了客戶端。 msg 的類型是 []byte

創(chuàng)建WebSocket客戶端

前端頁面路由對應(yīng)的請求處理程序如下,直接返回 views/websockets.html 給到瀏覽器渲染頁面即可。

?
1
2
3
4
5
6
7
8
// 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 服務(wù)進(jìn)行收發(fā)消息,篇幅原因我就只貼 JS 代碼了

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<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>
...

注冊路由

服務(wù)端和客戶端的程序都準(zhǔn)備好后,我們按照之前約定好的路徑為他們注冊路由和對應(yīng)的請求處理程序:

?
1
2
3
4
5
6
7
// router/router.go
func RegisterRoutes(r *mux.Router) {
 ...
 wsRouter := r.PathPrefix("/ws").Subrouter()
 wsRouter.HandleFunc("/echo", ws.EchoMessage)
 wsRouter.HandleFunc("/echo_display", ws.DisplayEcho)
}

測試驗(yàn)證

重啟服務(wù)后訪問 http://localhost:8000/ws/echo_display ,在輸入框中輸入任何消息都能再次回顯到瀏覽器中。

使用Go語言創(chuàng)建WebSocket服務(wù)的實(shí)現(xiàn)示例

服務(wù)端則是把收到的消息打印到終端中然后把調(diào)用 writeMessage 把消息再回傳給客戶端,可以在終端中查看到記錄。

使用Go語言創(chuàng)建WebSocket服務(wù)的實(shí)現(xiàn)示例

總結(jié)

WebSocket 在現(xiàn)在更新頻繁的應(yīng)用中使用非常廣泛,進(jìn)行 WebSocket 編程也是我們需要掌握的一項(xiàng)必備技能。文章的實(shí)踐練習(xí)稍微簡單了一些,也沒有做錯(cuò)誤和安全性檢查。主要是為了講清楚大概的流程。關(guān)于 gorilla/websocket 更多的細(xì)節(jié)在使用時(shí)還需要查看官方文檔才行。

參考鏈接:

https://yalantis.com/blog/how-to-build-websockets-in-go/

https://www.gorillatoolkit.org/pkg/websocket

到此這篇關(guān)于使用Go語言創(chuàng)建WebSocket服務(wù)的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Go語言創(chuàng)建WebSocket 內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://studygolang.com/articles/27258

延伸 · 閱讀

精彩推薦
  • Golanggo語言制作端口掃描器

    go語言制作端口掃描器

    本文給大家分享的是使用go語言編寫的TCP端口掃描器,可以選擇IP范圍,掃描的端口,以及多線程,有需要的小伙伴可以參考下。 ...

    腳本之家3642020-04-25
  • Golanggolang如何使用struct的tag屬性的詳細(xì)介紹

    golang如何使用struct的tag屬性的詳細(xì)介紹

    這篇文章主要介紹了golang如何使用struct的tag屬性的詳細(xì)介紹,從例子說起,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看...

    Go語言中文網(wǎng)11352020-05-21
  • Golanggolang的httpserver優(yōu)雅重啟方法詳解

    golang的httpserver優(yōu)雅重啟方法詳解

    這篇文章主要給大家介紹了關(guān)于golang的httpserver優(yōu)雅重啟的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,...

    helight2992020-05-14
  • Golanggo日志系統(tǒng)logrus顯示文件和行號的操作

    go日志系統(tǒng)logrus顯示文件和行號的操作

    這篇文章主要介紹了go日志系統(tǒng)logrus顯示文件和行號的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    SmallQinYan12302021-02-02
  • GolangGolang中Bit數(shù)組的實(shí)現(xiàn)方式

    Golang中Bit數(shù)組的實(shí)現(xiàn)方式

    這篇文章主要介紹了Golang中Bit數(shù)組的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    天易獨(dú)尊11682021-06-09
  • Golanggolang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法

    golang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法

    今天小編就為大家分享一篇golang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    李浩的life12792020-05-27
  • Golanggolang 通過ssh代理連接mysql的操作

    golang 通過ssh代理連接mysql的操作

    這篇文章主要介紹了golang 通過ssh代理連接mysql的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    a165861639710342021-03-08
  • GolangGolang通脈之?dāng)?shù)據(jù)類型詳情

    Golang通脈之?dāng)?shù)據(jù)類型詳情

    這篇文章主要介紹了Golang通脈之?dāng)?shù)據(jù)類型,在編程語言中標(biāo)識符就是定義的具有某種意義的詞,比如變量名、常量名、函數(shù)名等等,Go語言中標(biāo)識符允許由...

    4272021-11-24
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 久久99视频| 亚洲成av人片在线观看无 | 免费在线a | 日本中文一区二区 | 久久久av| 美女视频一区 | yy6080一级二级 | 91久久精品国产91久久 | 欧美电影在线观看网站 | 久久精品国产91精品亚洲高清 | 欧美精品一区二区三区蜜桃视频 | 小视频免费在线观看 | 日韩中文字幕在线播放 | zzzzyyyy精品国产 | 男人的天堂久久精品 | 伊人99 | 欧美一区二区日韩一区二区 | 夜久久 | 在线精品一区 | 日韩精品视频在线 | 亚洲欧美中文字幕 | 亚洲综合国产 | 国产精品v一区二区三区 | 最新毛片在线观看 | 国产精品国产精品国产专区不卡 | 亚洲一区在线视频 | 一本色道久久综合狠狠躁篇的优点 | 久久精品中文视频 | 亚洲精选久久 | 91嫩草精品| av一级毛片 | 中文字字幕一区二区三区四区五区 | 国产一区二区三区四 | 免费亚洲网站 | 成人综合电影网 | 中文字幕日韩av | 国产一区二区精品在线观看 | 国产日韩欧美精品 | 香蕉久久av一区二区三区 | 成年人毛片视频 | 在线成人av |