<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          使用 Go 和 ReactJS 構(gòu)建聊天系統(tǒng)(二):gorilla/websocket 包提供的 WebSockets

          共 5080字,需瀏覽 11分鐘

           ·

          2021-01-16 20:08

          點(diǎn)擊上方藍(lán)色“Go語言中文網(wǎng)”關(guān)注,每天一起學(xué) Go

          本節(jié)完整代碼:GitHub[1]

          本文是使用 ReactJS 和 Go 來構(gòu)建聊天應(yīng)用程序的系列文章的第 2 部分。你可以在這里找到第 1 部分 - 初始化設(shè)置[2]

          現(xiàn)在我們已經(jīng)建立好了基本的前端和后端,現(xiàn)在需要來完善一些功能了。

          在本節(jié)中,我們將實(shí)現(xiàn)一個基于 WebSocket 的服務(wù)器。

          在該系列教程結(jié)束時,我們將有一個可以于后端雙向通信的前端應(yīng)用程序。

          服務(wù)

          我們可以使用 github.com/gorilla/websocket 包來設(shè)置 WebSocket 服務(wù)以及處理 WebSocket 連接的讀寫操作。

          這需要在我們的 backend/ 目錄中運(yùn)行此命令來安裝它:

          $?go?get?github.com/gorilla/websocket

          一旦我們成功安裝了這個包,我們就可以開始構(gòu)建我們的 Web 服務(wù)了。我們首先創(chuàng)建一個非常簡單的 net/http 服務(wù):

          package?main

          import?(
          ?"fmt"
          ?"net/http"
          )

          func?setupRoutes()?{
          ?http.HandleFunc("/",?func(w?http.ResponseWriter,?r?*http.Request)?{
          ??fmt.Fprintf(w,?"Simple?Server")
          ?})
          }

          func?main()?{
          ?setupRoutes()
          ?http.ListenAndServe(":8080",?nil)
          }

          可以通過調(diào)用 go run main.go 來啟動服務(wù),該服務(wù)將監(jiān)聽 http://localhost:8080[3] 。如果用瀏覽器打開此連接,可以看到輸出 Simple Server

          WebSocket 協(xié)議

          在開始寫代碼之前,我們需要了解一下理論。

          WebSockets 可以通過 TCP 連接進(jìn)行雙工通信。這讓我們可以通過單個 TCP 套接字來發(fā)送和監(jiān)聽消息,從而避免通過輪詢 Web 服務(wù)器去通信,每次輪詢操作都會執(zhí)行 TCP 握手過程。

          WebSockets 大大減少了應(yīng)用程序所需的網(wǎng)絡(luò)帶寬,并且使得我們在單個服務(wù)器實(shí)例上維護(hù)大量客戶端。

          連接

          WebSockets 肯定有一些值得考慮的缺點(diǎn)。比如一旦引入狀態(tài),在跨多個實(shí)例擴(kuò)展應(yīng)用程序的時候就變得更加復(fù)雜。

          在這種場景下需要考慮更多的情況,例如將狀態(tài)存儲在消息代理中,或者存儲在數(shù)據(jù)庫/內(nèi)存緩存中。

          實(shí)現(xiàn)

          在實(shí)現(xiàn) WebSocket 服務(wù)時,我們需要創(chuàng)建一個端點(diǎn),然后將該端點(diǎn)的連接從標(biāo)準(zhǔn)的 HTTP 升級到 WebSocket。

          值得慶幸的是,gorilla/websocket 包提供了我們所需的功能,可以輕松地將 HTTP 連接升級到 WebSocket 連接。

          注意 - 你可以查看官方 WebSocket 協(xié)議的更多信息:RFC-6455[4]

          創(chuàng)建 WebSocket 服務(wù)端

          現(xiàn)在已經(jīng)了解了理論,來看看如何去實(shí)踐。我們創(chuàng)建一個新的端點(diǎn) /ws,我們將從標(biāo)準(zhǔn)的 http 端點(diǎn)轉(zhuǎn)換為 ws 端點(diǎn)。

          此端點(diǎn)將執(zhí)行 3 項(xiàng)操作,它將檢查傳入的 HTTP 請求,然后返回 true 以打開我們的端點(diǎn)到客戶端。然后,我們使用定義的 upgrader 升級為 WebSocket 連接。

          最后,我們將開始監(jiān)聽傳入的消息,然后將它們打印出來并將它們傳回相同的連接。這可以讓我們驗(yàn)證前端連接并從新創(chuàng)建的 WebSocket 端點(diǎn)來發(fā)送/接收消息:

          package?main

          import?(
          ?"fmt"
          ?"log"
          ?"net/http"

          ?"github.com/gorilla/websocket"
          )

          //?我們需要定義一個?Upgrader
          //?它需要定義?ReadBufferSize?和?WriteBufferSize
          var?upgrader?=?websocket.Upgrader{
          ?ReadBufferSize:??1024,
          ?WriteBufferSize:?1024,

          ?//?可以用來檢查連接的來源
          ?//?這將允許從我們的 React 服務(wù)向這里發(fā)出請求。
          ?//?現(xiàn)在,我們可以不需要檢查并運(yùn)行任何連接
          ?CheckOrigin:?func(r?*http.Request)?bool?{?return?true?},
          }

          //?定義一個?reader?用來監(jiān)聽往?WS?發(fā)送的新消息
          func?reader(conn?*websocket.Conn)?{
          ?for?{
          ??//?讀消息
          ??messageType,?p,?err?:=?conn.ReadMessage()
          ??if?err?!=?nil?{
          ???log.Println(err)
          ???return
          ??}
          ??//?打印消息
          ??fmt.Println(string(p))

          ??if?err?:=?conn.WriteMessage(messageType,?p);?err?!=?nil?{
          ???log.Println(err)
          ???return
          ??}
          ?}
          }

          //?定義?WebSocket?服務(wù)處理函數(shù)
          func?serveWs(w?http.ResponseWriter,?r?*http.Request)?{
          ?fmt.Println(r.Host)

          ?//?將連接更新為?WebSocket?連接
          ?ws,?err?:=?upgrader.Upgrade(w,?r,?nil)
          ?if?err?!=?nil?{
          ??log.Println(err)
          ?}

          ?//?一直監(jiān)聽?WebSocket?連接上傳來的新消息
          ?reader(ws)
          }

          func?setupRoutes()?{
          ?http.HandleFunc("/",?func(w?http.ResponseWriter,?r?*http.Request)?{
          ??fmt.Fprintf(w,?"Simple?Server")
          ?})

          ?//?將?`/ws`?端點(diǎn)交給?`serveWs`?函數(shù)處理
          ?http.HandleFunc("/ws",?serveWs)
          }

          func?main()?{
          ?fmt.Println("Chat?App?v0.01")
          ?setupRoutes()
          ?http.ListenAndServe(":8080",?nil)
          }

          如果沒有問題的話,我們使用 go run main.go 來啟動服務(wù)。

          客戶端

          現(xiàn)在已經(jīng)設(shè)置好了服務(wù),我們需要一些能夠與之交互的東西。這是我們的 ReactJS 前端發(fā)揮作用的地方。

          我們先盡量讓客戶端保持簡單,并定義一個 api/index.js 文件,它將包含 WebSocket 連接的代碼。

          //?api/index.js
          var?socket?=?new?WebSocket("ws://localhost:8080/ws");

          let?connect?=?()?=>?{
          ?console.log("Attempting?Connection...");

          ?socket.onopen?=?()?=>?{
          ??console.log("Successfully?Connected");
          ?};

          ?socket.onmessage?=?msg?=>?{
          ??console.log(msg);
          ?};

          ?socket.onclose?=?event?=>?{
          ??console.log("Socket?Closed?Connection:?",?event);
          ?};

          ?socket.onerror?=?error?=>?{
          ??console.log("Socket?Error:?",?error);
          ?};
          };

          let?sendMsg?=?msg?=>?{
          ?console.log("sending?msg:?",?msg);
          ?socket.send(msg);
          };

          export?{?connect,?sendMsg?};

          因此,在上面的代碼中,我們定義了我們隨后導(dǎo)出的 2 個函數(shù)。分別是 connect()sendMsg(msg)。

          第一個函數(shù),connect() 函數(shù),連接 WebSocket 端點(diǎn),并監(jiān)聽例如與 onopen 成功連接之類的事件。如果它發(fā)現(xiàn)任何問題,例如連接關(guān)閉的套接字或錯誤,它會將這些問題打印到瀏覽器控制臺。

          第二個函數(shù),sendMsg(msg) 函數(shù),允許我們使用 socket.send() 通過 WebSocket 連接從前端發(fā)送消息到后端。

          現(xiàn)在我們在 React 項(xiàng)目中更新 App.js 文件,添加對 connect() 的調(diào)用并創(chuàng)建一個觸發(fā) sendMsg() 函數(shù)的



          推薦閱讀


          福利

          我為大家整理了一份從入門到進(jìn)階的Go學(xué)習(xí)資料禮包,包含學(xué)習(xí)建議:入門看什么,進(jìn)階看什么。關(guān)注公眾號 「polarisxu」,回復(fù) ebook 獲??;還可以回復(fù)「進(jìn)群」,和數(shù)萬 Gopher 交流學(xué)習(xí)。

          瀏覽 27
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  AV噜噜噜 | 很很日2012中文在线免费 | 欧美日韩A片黄色电影视频 | 黄色视频在线免费直播 | 久草一区 |