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

Go語(yǔ)言中websocket的使用demo分享

 更新時(shí)間:2022年12月28日 10:45:45   作者:用戶6512516549724  
WebSocket是一種在單個(gè)TCP連接上進(jìn)行全雙工通信的協(xié)議。這篇文章主要和大家分享了一個(gè)Go語(yǔ)言中websocket的使用demo,需要的可以參考一下

服務(wù)端代碼 main.go

package main

import (
   "errors"
   "fmt"
   "net/http"
   "sync"
   "time"

   "github.com/gorilla/websocket"
)

// http升級(jí)websocket協(xié)議的配置
var wsUpgrader = websocket.Upgrader{
   // 允許所有CORS跨域請(qǐng)求
   CheckOrigin: func(r *http.Request) bool {
      return true
   },
}

// 客戶端讀寫消息
type wsMessage struct {
   messageType int
   data        []byte
}

// 客戶端連接
type wsConnection struct {
   wsSocket *websocket.Conn // 底層websocket
   inChan   chan *wsMessage // 讀隊(duì)列
   outChan  chan *wsMessage // 寫隊(duì)列

   mutex     sync.Mutex // 避免重復(fù)關(guān)閉管道
   isClosed  bool
   closeChan chan byte // 關(guān)閉通知
}

func (wsConn *wsConnection) wsReadLoop() {
   for {
      // 讀一個(gè)message
      msgType, data, err := wsConn.wsSocket.ReadMessage()
      if err != nil {
         goto error
      }
      req := &wsMessage{
         msgType,
         data,
      }
      // 放入請(qǐng)求隊(duì)列
      select {
      case wsConn.inChan <- req:
      case <-wsConn.closeChan:
         goto closed
      }
   }
error:
   wsConn.wsClose()
closed:
}

func (wsConn *wsConnection) wsWriteLoop() {
   for {
      select {
      // 取一個(gè)應(yīng)答
      case msg := <-wsConn.outChan:
         // 寫給websocket
         if err := wsConn.wsSocket.WriteMessage(msg.messageType, msg.data); err != nil {
            goto error
         }
      case <-wsConn.closeChan:
         goto closed
      }
   }
error:
   wsConn.wsClose()
closed:
}

func (wsConn *wsConnection) procLoop() {
   // 啟動(dòng)一個(gè)gouroutine發(fā)送心跳
   go func() {
      for { //不斷向客戶端寫數(shù)據(jù),其實(shí)沒有它也是一樣的,客戶端可以檢測(cè)到斷開
         time.Sleep(2 * time.Second)
         if err := wsConn.wsWrite(websocket.TextMessage, []byte("heartbeat from server")); err != nil {
            fmt.Println("heartbeat fail")
            wsConn.wsClose()
            break
         }
      }
   }()

   // 這是一個(gè)同步處理模型(只是一個(gè)例子),如果希望并行處理可以每個(gè)請(qǐng)求一個(gè)gorutine,注意控制并發(fā)goroutine的數(shù)量!!!
   for {
      msg, err := wsConn.wsRead()
      if err != nil {
         fmt.Println("read fail")
         break
      }
      fmt.Println(string(msg.data))
      err = wsConn.wsWrite(msg.messageType, msg.data) // 讀到數(shù)據(jù)后,同步的去寫數(shù)據(jù)。應(yīng)該寫成異步
      if err != nil {
         fmt.Println("write fail")
         break
      }
   }
}

func wsHandler(resp http.ResponseWriter, req *http.Request) {
   // 應(yīng)答客戶端告知升級(jí)連接為websocket
   wsSocket, err := wsUpgrader.Upgrade(resp, req, nil)
   if err != nil {
      return
   }
   wsConn := &wsConnection{
      wsSocket:  wsSocket,
      inChan:    make(chan *wsMessage, 1000),
      outChan:   make(chan *wsMessage, 1000),
      closeChan: make(chan byte),
      isClosed:  false,
   }

   // 處理器
   go wsConn.procLoop()
   // 讀協(xié)程
   go wsConn.wsReadLoop()
   // 寫協(xié)程
   go wsConn.wsWriteLoop()
}

func (wsConn *wsConnection) wsWrite(messageType int, data []byte) error {
   select {
   case wsConn.outChan <- &wsMessage{messageType, data}:
   case <-wsConn.closeChan:
      return errors.New("websocket closed")
   }
   return nil
}

func (wsConn *wsConnection) wsRead() (*wsMessage, error) {
   select {
   case msg := <-wsConn.inChan:
      return msg, nil
   case <-wsConn.closeChan:
   }
   return nil, errors.New("websocket closed")
}

func (wsConn *wsConnection) wsClose() {
   wsConn.wsSocket.Close()

   wsConn.mutex.Lock()
   defer wsConn.mutex.Unlock()
   if !wsConn.isClosed {
      wsConn.isClosed = true
      close(wsConn.closeChan)
   }
}

func main() {
   http.HandleFunc("/ws", wsHandler)
   http.ListenAndServe("0.0.0.0:7777", nil)
}

前端代碼 client.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <script>
        window.addEventListener("load", function(evt) {
            const output = document.getElementById("output");
            const input = document.getElementById("input");
            let ws;
            const print = function(message) {
                const d = document.createElement("div");
                d.innerHTML = message;
                output.appendChild(d);
            };
            document.getElementById("open").onclick = function(evt) {
                if (ws) {
                    return false;
                }
                ws = new WebSocket("ws://localhost:7777/ws");
                ws.onopen = function(evt) {
                    print("OPEN");
                }
                ws.onclose = function(evt) {
                    print("CLOSE");
                    ws = null;
                }
                ws.onmessage = function(evt) {
                    print("RESPONSE: " + evt.data);
                }
                ws.onerror = function(evt) {
                    print("ERROR: " + evt.data);
                }
                return false;
            };
            document.getElementById("send").onclick = function(evt) {
                if (!ws) {
                    return false;
                }
                print("SEND: " + input.value);
                ws.send(input.value);
                return false;
            };
            document.getElementById("close").onclick = function(evt) {
                if (!ws) {
                    return false;
                }
                ws.close();
                return false;
            };
        });
    </script>
</head>
<body>
<table>
    <tr><td valign="top" width="50%">
        <p>Click "Open" to create a connection to the server,
            "Send" to send a message to the server and "Close" to close the connection.
            You can change the message and send multiple times.
        </p>
            <form>
                <button id="open">Open</button>
                <button id="close">Close</button>
            <input id="input" type="text" value="Hello world!">
            <button id="send">Send</button>
            </form>
    </td><td valign="top" width="50%">
        <div id="output"></div>
    </td></tr></table>
</body>
</html>

到此這篇關(guān)于Go語(yǔ)言中websocket的使用demo分享的文章就介紹到這了,更多相關(guān)Go語(yǔ)言 websocket內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang中的同步工具sync.Map示例詳解

    Golang中的同步工具sync.Map示例詳解

    sync.Map是Golang標(biāo)準(zhǔn)庫(kù)提供的并發(fā)安全的Map類型,可以在多個(gè)goroutine并發(fā)讀寫Map的場(chǎng)景下不需要加鎖,這篇文章主要介紹了Golang中的同步工具sync.Map詳解,需要的朋友可以參考下
    2023-05-05
  • Golang全局變量加鎖的問(wèn)題解決

    Golang全局變量加鎖的問(wèn)題解決

    這篇文章主要介紹了解決Golang全局變量加鎖的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-05-05
  • Golang flag包的具體使用

    Golang flag包的具體使用

    本文主要介紹了Golang flag包的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • Golang 實(shí)現(xiàn) Redis系列(六)如何實(shí)現(xiàn) pipeline 模式的 redis 客戶端

    Golang 實(shí)現(xiàn) Redis系列(六)如何實(shí)現(xiàn) pipeline 模式的 redis 客戶端

    pipeline 模式的 redis 客戶端需要有兩個(gè)后臺(tái)協(xié)程負(fù)責(zé) tcp 通信,調(diào)用方通過(guò) channel 向后臺(tái)協(xié)程發(fā)送指令,并阻塞等待直到收到響應(yīng),本文是使用 golang 實(shí)現(xiàn) redis 系列的第六篇, 將介紹如何實(shí)現(xiàn)一個(gè) Pipeline 模式的 Redis 客戶端。
    2021-07-07
  • Go語(yǔ)言中rune方法使用詳解

    Go語(yǔ)言中rune方法使用詳解

    本文主要介紹了Go語(yǔ)言中rune方法使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • 使用Go語(yǔ)言實(shí)現(xiàn)配置文件熱加載功能

    使用Go語(yǔ)言實(shí)現(xiàn)配置文件熱加載功能

    這篇文章主要介紹了使用Go語(yǔ)言實(shí)現(xiàn)配置文件熱加載功能,以及配置文件熱加載包的實(shí)現(xiàn)思路,需要的朋友可以參考下
    2018-03-03
  • Go語(yǔ)言下載網(wǎng)絡(luò)圖片或文件的方法示例

    Go語(yǔ)言下載網(wǎng)絡(luò)圖片或文件的方法示例

    這篇文章主要介紹了Go語(yǔ)言下載網(wǎng)絡(luò)圖片或文件的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • 使用Go語(yǔ)言生成二維碼并在命令行中輸出

    使用Go語(yǔ)言生成二維碼并在命令行中輸出

    二維碼(QR code)是一種矩陣條碼的標(biāo)準(zhǔn),廣泛應(yīng)用于商業(yè)、移動(dòng)支付和數(shù)據(jù)存儲(chǔ)等領(lǐng)域,在開發(fā)過(guò)程中,我們可能需要在命令行中顯示二維碼,這可以幫助我們快速生成和分享二維碼信息,本文將介紹如何使用Go語(yǔ)言生成二維碼并在命令行中輸出,需要的朋友可以參考下
    2023-11-11
  • golang通過(guò)context控制并發(fā)的應(yīng)用場(chǎng)景實(shí)現(xiàn)

    golang通過(guò)context控制并發(fā)的應(yīng)用場(chǎng)景實(shí)現(xiàn)

    這篇文章主要介紹了golang通過(guò)context控制并發(fā)的應(yīng)用場(chǎng)景實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • Go時(shí)間格式化的實(shí)現(xiàn)

    Go時(shí)間格式化的實(shí)現(xiàn)

    本文主要介紹了Go時(shí)間格式化的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06

最新評(píng)論