校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃

主頁 > 知識庫 > golang websocket 服務端的實現

golang websocket 服務端的實現

熱門標簽:學海導航地圖標注 南通如皋申請開通400電話 高德地圖標注口訣 地圖標注的汽車標 中國地圖標注省會高清 浙江高速公路地圖標注 廣州呼叫中心外呼系統 江西轉化率高的羿智云外呼系統 西部云谷一期地圖標注

創建一個websocket的服務端

package smile

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

  "github.com/gorilla/websocket"
)

const (
  // 允許等待的寫入時間
  writeWait = 10 * time.Second

  // Time allowed to read the next pong message from the peer.
  pongWait = 60 * time.Second

  // Send pings to peer with this period. Must be less than pongWait.
  pingPeriod = (pongWait * 9) / 10

  // Maximum message size allowed from peer.
  maxMessageSize = 512
)

// 最大的連接ID,每次連接都加1 處理
var maxConnId int64

// 客戶端讀寫消息
type wsMessage struct {
  // websocket.TextMessage 消息類型
  messageType int
  data    []byte
}

// ws 的所有連接
// 用于廣播
var wsConnAll map[int64]*wsConnection

var upgrader = websocket.Upgrader{
  ReadBufferSize: 1024,
  WriteBufferSize: 1024,
  // 允許所有的CORS 跨域請求,正式環境可以關閉
  CheckOrigin: func(r *http.Request) bool {
    return true
  },
}

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

  mutex   sync.Mutex // 避免重復關閉管道,加鎖處理
  isClosed bool
  closeChan chan byte // 關閉通知
  id    int64
}

func wsHandler(resp http.ResponseWriter, req *http.Request) {
  // 應答客戶端告知升級連接為websocket
  wsSocket, err := upgrader.Upgrade(resp, req, nil)
  if err != nil {
    log.Println("升級為websocket失敗", err.Error())
    return
  }
  maxConnId++
  // TODO 如果要控制連接數可以計算,wsConnAll長度
  // 連接數保持一定數量,超過的部分不提供服務
  wsConn := wsConnection{
    wsSocket: wsSocket,
    inChan:  make(chan *wsMessage, 1000),
    outChan:  make(chan *wsMessage, 1000),
    closeChan: make(chan byte),
    isClosed: false,
    id:    maxConnId,
  }
  wsConnAll[maxConnId] = wsConn
  log.Println("當前在線人數", len(wsConnAll))

  // 處理器,發送定時信息,避免意外關閉
  go wsConn.processLoop()
  // 讀協程
  go wsConn.wsReadLoop()
  // 寫協程
  go wsConn.wsWriteLoop()
}

// 處理隊列中的消息
func (wsConn *wsConnection) processLoop() {
  // 處理消息隊列中的消息
  // 獲取到消息隊列中的消息,處理完成后,發送消息給客戶端
  for {
    msg, err := wsConn.wsRead()
    if err != nil {
      log.Println("獲取消息出現錯誤", err.Error())
      break
    }
    log.Println("接收到消息", string(msg.data))
    // 修改以下內容把客戶端傳遞的消息傳遞給處理程序
    err = wsConn.wsWrite(msg.messageType, msg.data)
    if err != nil {
      log.Println("發送消息給客戶端出現錯誤", err.Error())
      break
    }
  }
}

// 處理消息隊列中的消息
func (wsConn *wsConnection) wsReadLoop() {
  // 設置消息的最大長度
  wsConn.wsSocket.SetReadLimit(maxMessageSize)
  wsConn.wsSocket.SetReadDeadline(time.Now().Add(pongWait))
  for {
    // 讀一個message
    msgType, data, err := wsConn.wsSocket.ReadMessage()
    if err != nil {
      websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure)
      log.Println("消息讀取出現錯誤", err.Error())
      wsConn.close()
      return
    }
    req := wsMessage{
      msgType,
      data,
    }
    // 放入請求隊列,消息入棧
    select {
    case wsConn.inChan - req:
    case -wsConn.closeChan:
      return
    }
  }
}

// 發送消息給客戶端
func (wsConn *wsConnection) wsWriteLoop() {
  ticker := time.NewTicker(pingPeriod)
  defer func() {
    ticker.Stop()
  }()
  for {
    select {
    // 取一個應答
    case msg := -wsConn.outChan:
      // 寫給websocket
      if err := wsConn.wsSocket.WriteMessage(msg.messageType, msg.data); err != nil {
        log.Println("發送消息給客戶端發生錯誤", err.Error())
        // 切斷服務
        wsConn.close()
        return
      }
    case -wsConn.closeChan:
      // 獲取到關閉通知
      return
    case -ticker.C:
      // 出現超時情況
      wsConn.wsSocket.SetWriteDeadline(time.Now().Add(writeWait))
      if err := wsConn.wsSocket.WriteMessage(websocket.PingMessage, nil); err != nil {
        return
      }
    }
  }
}

// 寫入消息到隊列中
func (wsConn *wsConnection) wsWrite(messageType int, data []byte) error {
  select {
  case wsConn.outChan - wsMessage{messageType, data}:
  case -wsConn.closeChan:
    return errors.New("連接已經關閉")
  }
  return nil
}

// 讀取消息隊列中的消息
func (wsConn *wsConnection) wsRead() (*wsMessage, error) {
  select {
  case msg := -wsConn.inChan:
    // 獲取到消息隊列中的消息
    return msg, nil
  case -wsConn.closeChan:

  }
  return nil, errors.New("連接已經關閉")
}

// 關閉連接
func (wsConn *wsConnection) close() {
  log.Println("關閉連接被調用了")
  wsConn.wsSocket.Close()
  wsConn.mutex.Lock()
  defer wsConn.mutex.Unlock()
  if wsConn.isClosed == false {
    wsConn.isClosed = true
    // 刪除這個連接的變量
    delete(wsConnAll, wsConn.id)
    close(wsConn.closeChan)
  }
}

// 啟動程序
func StartWebsocket(addrPort string) {
  wsConnAll = make(map[int64]*wsConnection)
  http.HandleFunc("/ws", wsHandler)
  http.ListenAndServe(addrPort, nil)
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

您可能感興趣的文章:
  • golang基于websocket實現的簡易聊天室程序
  • Golang使用WebSocket通信的實現
  • 一百行Golang代碼實現簡單并發聊天室
  • golang實現一個簡單的websocket聊天室功能

標簽:貴州 常州 保定 德宏 曲靖 吐魯番 許昌 東營

巨人網絡通訊聲明:本文標題《golang websocket 服務端的實現》,本文關鍵詞  golang,websocket,服務,端,的,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《golang websocket 服務端的實現》相關的同類信息!
  • 本頁收集關于golang websocket 服務端的實現的相關信息資訊供網民參考!
  • 推薦文章
    校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃
    久久国产精品免费| 国产馆精品极品| 一区二区三区中文字幕精品精品 | 亚洲夂夂婷婷色拍ww47| 国产精品久久二区二区| 精品国产三级电影在线观看| 欧美日韩久久久| 蜜臀av性久久久久蜜臀av麻豆| 一区二区三区在线免费视频| 一区二区三区在线观看网站| 亚洲免费av观看| 中文字幕一区二区三区在线播放| 精品国产一区二区三区不卡| 26uuu另类欧美| 精品国产乱码久久久久久影片| 欧美剧情电影在线观看完整版免费励志电影| 在线一区二区三区| 色综合久久久久网| 欧美最新大片在线看| 不卡的av电影在线观看| 欧美影片第一页| 欧洲一区二区三区在线| 91麻豆精品国产| 欧美一二三四区在线| 日韩欧美电影一二三| 欧美日产在线观看| 欧美日韩精品专区| 91精品在线麻豆| 欧美三级视频在线| 日韩欧美国产精品一区| 日韩欧美综合一区| 久久久亚洲综合| 亚洲精品亚洲人成人网在线播放| 一区二区在线免费| 亚洲夂夂婷婷色拍ww47| 久久99这里只有精品| 国产伦精一区二区三区| 国产suv一区二区三区88区| 国产成人av资源| 色噜噜狠狠一区二区三区果冻| 在线精品视频小说1| 欧美怡红院视频| 久久新电视剧免费观看| 国产精品不卡视频| 亚洲线精品一区二区三区| 精品一区二区三区免费观看 | 欧美精品1区2区| 9191国产精品| 国产精品国产三级国产aⅴ中文| 一区二区视频在线| 秋霞影院一区二区| 99精品国产99久久久久久白柏| 91视频在线观看| 91麻豆精品国产91久久久久| 日韩精品一区二区三区在线观看 | 日韩一区二区麻豆国产| 国产色产综合色产在线视频| 一区二区三区免费看视频| 日韩成人精品在线| 国产大陆a不卡| 欧美精品在线观看播放| 国产欧美精品区一区二区三区| 亚洲天堂福利av| 伊人开心综合网| 丁香一区二区三区| 欧美日韩一区三区| 国产免费成人在线视频| 日本一道高清亚洲日美韩| 国产成人综合自拍| 欧美视频一区二区三区四区 | 欧美一区午夜视频在线观看| 中文一区二区完整视频在线观看| 午夜精品久久一牛影视| 国产aⅴ精品一区二区三区色成熟| 91丨九色丨黑人外教| 国产欧美日韩在线| 五月天一区二区三区| 成人激情图片网| 久久久精品蜜桃| 日韩经典一区二区| 91污片在线观看| 日韩美一区二区三区| 亚洲宅男天堂在线观看无病毒| 国产乱码精品1区2区3区| 色一区在线观看| 成人免费在线视频| 国产乱码精品一品二品| 日韩亚洲欧美高清| 视频一区视频二区中文字幕| av在线不卡网| 久久久精品天堂| 国产麻豆成人精品| 日韩免费一区二区三区在线播放| 一区二区理论电影在线观看| 国产精品88av| 国产午夜亚洲精品理论片色戒| 日本中文字幕一区二区有限公司| 91久久国产最好的精华液| 亚洲色图色小说| a美女胸又www黄视频久久| 久久久久久综合| 日本不卡视频在线观看| 欧美日韩精品二区第二页| 亚洲美女一区二区三区| 国产美女视频一区| 久久久久久日产精品| 毛片av一区二区| 欧美日本在线看| 美女视频黄免费的久久| 91精品国模一区二区三区| 亚洲超碰97人人做人人爱| 精品视频在线免费| 亚洲成年人影院| 欧美三片在线视频观看| 亚洲免费在线电影| 日本精品免费观看高清观看| 中文字幕亚洲在| 国产精华液一区二区三区| 中文在线资源观看网站视频免费不卡| 国产在线精品国自产拍免费| 欧美r级在线观看| 国产一区二区三区免费在线观看| 精品国精品国产| 韩日av一区二区| 日韩免费观看高清完整版在线观看| 国内精品伊人久久久久av影院| 欧美岛国在线观看| 青青草国产精品亚洲专区无| 精品国产123| 国产精品一区二区在线播放| 欧美国产一区在线| 色婷婷av一区二区三区大白胸| 依依成人精品视频| 欧洲精品一区二区| 久久av资源站| 国产精品热久久久久夜色精品三区 | 精品国产3级a| 国产剧情av麻豆香蕉精品| 亚洲国产精品成人综合| 国产成人免费在线观看不卡| 亚洲精品乱码久久久久久日本蜜臀| 日本韩国欧美一区二区三区| 亚洲国产cao| 日韩欧美国产麻豆| 又紧又大又爽精品一区二区| 欧美精品欧美精品系列| 国产在线看一区| www.日韩在线| 偷偷要91色婷婷| 国产精品久久久久久一区二区三区 | 美女任你摸久久| 国产精品久久久久久久久快鸭 | 欧美私模裸体表演在线观看| 国精产品一区一区三区mba桃花| 午夜久久久久久久久久一区二区| 日韩午夜精品电影| 91女神在线视频| 麻豆国产精品777777在线| 中文字幕人成不卡一区| 日韩欧美一级二级三级久久久| 91亚洲精华国产精华精华液| 久久av资源站| 亚洲一区二区av在线| 亚洲国产精品激情在线观看| 在线成人av影院| 92精品国产成人观看免费| 麻豆精品国产91久久久久久| 亚洲精品日韩综合观看成人91| 久久看人人爽人人| 在线播放国产精品二区一二区四区 | 一本大道久久精品懂色aⅴ| 狠狠色狠狠色综合系列| 天堂一区二区在线| 亚洲三级在线免费| 久久精品亚洲国产奇米99 | 丝袜亚洲另类欧美| 亚洲欧美另类图片小说| 久久久一区二区三区| 日韩三级在线免费观看| 欧美日韩一区二区三区在线| 99国产欧美久久久精品| 国产黄色91视频| 久久电影国产免费久久电影| 亚洲国产视频一区| 亚洲精品ww久久久久久p站| 国产精品久久三区| 日本一区二区免费在线观看视频| 日韩一卡二卡三卡| 欧美日本精品一区二区三区| 日本精品一区二区三区高清| av在线不卡电影| 99久久伊人久久99| 成人激情动漫在线观看| 国产成人亚洲综合a∨婷婷| 久久99精品网久久| 激情都市一区二区| 韩国欧美一区二区| 国产毛片精品一区| 国产一区不卡在线| 国产很黄免费观看久久|