<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Golang websocket推送

      Golang websocket推送

      在工作用主要使用的是Java,也做過IM(后端用的netty websocket)。最近想通過Golang重寫下,于是通過websocket擼了一個(gè)聊天室。

      項(xiàng)目地址

      Github

      依賴

      golang.org/x/net下的websocket。

      由于我使用的是golang版本是1.12,在國內(nèi)訪問golang.org/x需要借助代理,或者通過replace替換為github下的鏡像。

      module github.com/xuanbo/pusher
      
      require golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3
      
      replace (
              golang.org/x/crypto => github.com/golang/crypto v0.0.0-20190308221718-c2843e01d9a2
              golang.org/x/net => github.com/golang/net v0.0.0-20190404232315-eb5bcb51f2a3
              golang.org/x/sys => github.com/golang/sys v0.0.0-20190215142949-d0b11bdaac8a
              golang.org/x/text => github.com/golang/text v0.3.0
      )
      

      即工程下的go.mod.cn文件。

      websocket用法

      核心就是for循環(huán)下的處理收到的消息邏輯,然后對消息進(jìn)行處理(轉(zhuǎn)發(fā)、廣播等)。

      // websocket Handler
      // usage: http.Handle("/websocket", websocket.Handler(pusher.Handler))
      func Handler(conn *websocket.Conn) {
      	// handle connected
      	var userId string
      	var err error
      	if userId, err = doConnected(conn); err != nil {
      		fmt.Println("Client connect error: ", err)
      		return
      	}
      
      	fmt.Println("Client connected, userId: ", userId)
      
      	for {
      		msg := new(Message)
      
      		if err := websocket.JSON.Receive(conn, msg); err != nil {
      			fmt.Println("Can't receive, error: ", err)
      			break
      		}
      
      		msg.UpdateAt = Timestamp()
      
      		fmt.Println("Received from client: ", msg)
      
      		// handle received message
      		if err := doReceived(conn, msg); err != nil {
      			fmt.Println("Received message error: ", err)
      			break
      		}
      	}
      
      	// handle disConnected
      	if err := doDisConnected(userId, conn); err != nil {
      		fmt.Println("Client disconnected error: ", err)
      		return
      	}
      
      	fmt.Println("Client disconnected, userId: ", userId)
      }
      

      連接管理

      在IM中比較重要的點(diǎn)就是管理客戶端連接,這樣我們才能通過服務(wù)端轉(zhuǎn)發(fā)消息給對應(yīng)的用戶。注意,下面沒有考慮集群,只在單機(jī)中考慮。

      // websocket connection manager
      type ConnManager struct {
      	// websocket connection number
      	Online *int32
      	// websocket connection
      	connections *sync.Map
      }
      

      上面定義了一個(gè)連接管理結(jié)構(gòu)體,Online為在線的人數(shù),connections為客戶端的連接管理(key為userId,value為websocket connection)。

      下面為ConnManager添加一些方法來處理連接、斷開連接、發(fā)送消息、廣播等操作。

      // add websocket connection
      // online number + 1
      func (m *ConnManager) Connected(k, v interface{}) {
      	m.connections.Store(k, v)
      
      	atomic.AddInt32(m.Online, 1)
      }
      
      // remove websocket connection by key
      // online number - 1
      func (m *ConnManager) DisConnected(k interface{}) {
      	m.connections.Delete(k)
      
      	atomic.AddInt32(m.Online, -1)
      }
      
      // get websocket connection by key
      func (m *ConnManager) Get(k interface{}) (v interface{}, ok bool) {
      	return m.connections.Load(k)
      }
      
      // iter websocket connections
      func (m *ConnManager) Foreach(f func(k, v interface{})) {
      	m.connections.Range(func(k, v interface{}) bool {
      		f(k, v)
      		return true
      	})
      }
      
      // send message to one websocket connection
      func (m *ConnManager) Send(k string, msg *Message) {
      	v, ok := m.Get(k)
      	if ok {
      		if conn, ok := v.(*websocket.Conn); ok {
      			if err := websocket.JSON.Send(conn, msg); err != nil {
      				fmt.Println("Send msg error: ", err)
      			}
      		} else {
      			fmt.Println("invalid type, expect *websocket.Conn")
      		}
      	} else {
      		fmt.Println("connection not exist")
      	}
      }
      
      // send message to multi websocket connections
      func (m *ConnManager) SendMulti(keys []string, msg interface{}) {
      	for _, k := range keys {
      		v, ok := m.Get(k)
      		if ok {
      			if conn, ok := v.(*websocket.Conn); ok {
      				if err := websocket.JSON.Send(conn, msg); err != nil {
      					fmt.Println("Send msg error: ", err)
      				}
      			} else {
      				fmt.Println("invalid type, expect *websocket.Conn")
      			}
      		} else {
      			fmt.Println("connection not exist")
      		}
      	}
      }
      
      // broadcast message to all websocket connections otherwise own connection
      func (m *ConnManager) Broadcast(conn *websocket.Conn, msg *Message) {
      	m.Foreach(func(k, v interface{}) {
      		if c, ok := v.(*websocket.Conn); ok && c != conn {
      			if err := websocket.JSON.Send(c, msg); err != nil {
      				fmt.Println("Send msg error: ", err)
      			}
      		}
      	})
      }
      

      消息類型、格式

      消息類型(MessageType)主要有單聊、群聊、系統(tǒng)通知等。

      消息格式(MediaType)主要有文本格式、圖片、文件等。

      type MessageType int
      type MediaType int
      
      const (
      	Single MessageType = iota
      	Group
      	SysNotify
      	OnlineNotify
      	OfflineNotify
      )
      
      const (
      	Text MediaType = iota
      	Image
      	File
      )
      
      // websocket message
      type Message struct {
      	MessageType MessageType `json:"messageType"`
      	MediaType   MediaType   `json:"mediaType"`
      	From        string      `json:"from"`
      	To          string      `json:"to"`
      	Content     string      `json:"content,omitempty"`
      	FileId      string      `json:"fileId,omitempty"`
      	Url         string      `json:"url,omitempty"`
      	CreateAt    int64       `json:"createAt,omitempty"`
      	UpdateAt    int64       `json:"updateAt,omitempty"`
      }
      

      上面定義了一個(gè)統(tǒng)一的消息(Message)。

      效果

      前端的代碼就不展示了,最終實(shí)現(xiàn)的聊天室效果如下:

      UI

      補(bǔ)充

      本例子沒有涉及到用戶認(rèn)證、消息加密、idle、單聊、消息格式、消息持久化等等,只做了一個(gè)簡單的群聊。

      歡迎感興趣的道友,基于此擴(kuò)展出自己的推送系統(tǒng)、IM等。

      說明

      Just for fun!

      posted @ 2019-04-16 15:29  bener  閱讀(3719)  評論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 亚洲精品国产精品乱码不| 国产高跟黑色丝袜在线| 内射无套内射国产精品视频| 制服丝袜长腿无码专区第一页| 鲁一鲁一鲁一鲁一澡| 1000部精品久久久久久久久| 亚洲成av人片在www鸭子| 亚洲综合另类小说色区一| 日本道高清一区二区三区| 午夜大片免费男女爽爽影院| 四子王旗| 果冻传媒一区二区天美传媒| 国产精品 无码专区| 日韩人妻无码精品久久| 久久精品午夜视频| 人妻少妇精品久久| 国产成人亚洲综合图区| 乱人伦中文视频在线| 国产中文字幕精品喷潮| 亚洲欧美在线观看品| 无码人妻一区二区三区在线视频| 国产成人亚洲综合图区| 国产一区二区精品偷系列| 国产+亚洲+制服| 久久国产乱子伦免费精品无码| 亚洲最大色综合成人av| 亚洲精品日本久久一区二区三区| 日韩丝袜欧美人妻制服| 国产一区二区三区四区色| 国产区二区三区在线观看| 亚洲精品一区二区区别| 久久国内精品一区二区三区| 综合亚洲网| 一区二区三区AV波多野结衣| 一区二区三区四区自拍视频| 狠狠色综合久久狠狠色综合| av无码小缝喷白浆在线观看| 亚洲国产精品自产拍久久| 性无码一区二区三区在线观看| 曝光无码有码视频专区| 天天澡日日澡狠狠欧美老妇|