最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言中websocket的使用demo分享

 更新時(shí)間:2022年12月28日 10:45:45   作者:用戶6512516549724  
WebSocket是一種在單個(gè)TCP連接上進(jìn)行全雙工通信的協(xié)議。這篇文章主要和大家分享了一個(gè)Go語言中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語言中websocket的使用demo分享的文章就介紹到這了,更多相關(guān)Go語言 websocket內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • golang 實(shí)現(xiàn)struct、json、map互相轉(zhuǎn)化

    golang 實(shí)現(xiàn)struct、json、map互相轉(zhuǎn)化

    這篇文章主要介紹了golang 實(shí)現(xiàn)struct、json、map互相轉(zhuǎn)化,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang中ringbuffer的實(shí)現(xiàn)與應(yīng)用場(chǎng)景詳解

    Golang中ringbuffer的實(shí)現(xiàn)與應(yīng)用場(chǎng)景詳解

    ringbuffer因?yàn)樗軓?fù)用緩沖空間,通常用于網(wǎng)絡(luò)通信連接的讀寫,雖然市面上已經(jīng)有了go寫的諸多版本的ringbuffer組件,但還是自己造一個(gè)吧
    2023-06-06
  • 淺談Go語言中字符串和數(shù)組

    淺談Go語言中字符串和數(shù)組

    這篇文章主要簡(jiǎn)單介紹了Go語言中字符串和數(shù)組的使用方法和申明方式,需要的朋友可以參考下
    2015-01-01
  • go MethodByName()不能獲取私有方法的解決

    go MethodByName()不能獲取私有方法的解決

    本文主要介紹了go MethodByName()不能獲取私有方法的解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • golang之log rotate詳解

    golang之log rotate詳解

    下面小編就為大家?guī)硪黄猤olang之log rotate詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • golang sql語句超時(shí)控制方案及原理

    golang sql語句超時(shí)控制方案及原理

    一般應(yīng)用程序在執(zhí)行一條sql語句時(shí),都會(huì)給這條sql設(shè)置一個(gè)超時(shí)時(shí)間,本文主要介紹了golang sql語句超時(shí)控制方案及原理,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-12-12
  • 使用Go語言實(shí)現(xiàn)微信公眾平臺(tái)

    使用Go語言實(shí)現(xiàn)微信公眾平臺(tái)

    這篇文章主要介紹了使用Go語言實(shí)現(xiàn)微信公眾平臺(tái),雖然不是全部代碼,但是也是給我們提供了一個(gè)非常好的思路,需要的朋友可以參考下
    2015-01-01
  • Go語言中的if條件語句使用詳解

    Go語言中的if條件語句使用詳解

    這篇文章主要介紹了Go語言中的if條件語句的使用,包括if...else語句以及相關(guān)嵌套,需要的朋友可以參考下
    2015-10-10
  • Golang巧用defer進(jìn)行錯(cuò)誤處理的方法

    Golang巧用defer進(jìn)行錯(cuò)誤處理的方法

    錯(cuò)誤處理是程序的重要組成部分,有效且優(yōu)雅的處理錯(cuò)誤是大多數(shù)程序員的追求,下面這篇文章主要給大家介紹了關(guān)于Golang中巧用defer進(jìn)行錯(cuò)誤處理的方法,文中通過示例介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。
    2017-05-05
  • 淺談golang二進(jìn)制bit位的常用操作

    淺談golang二進(jìn)制bit位的常用操作

    這篇文章主要介紹了淺談golang二進(jìn)制bit位的常用操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12

最新評(píng)論

房山区| 宁城县| 剑河县| 泌阳县| 河西区| 葫芦岛市| 巴彦淖尔市| 杨浦区| 桓台县| 连江县| 铜鼓县| 华池县| 迭部县| 呈贡县| 岑巩县| 井冈山市| 鄱阳县| 万山特区| 武义县| 天津市| 金乡县| 辽阳县| 革吉县| 渑池县| 花莲市| 思茅市| 灌阳县| 中卫市| 沂源县| 普陀区| 阜新| 容城县| 武安市| 三都| 运城市| 阳春市| 永登县| 兴安县| 荆州市| 德化县| 沽源县|