您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Go使用websocket實現彈幕功能的方法,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
下面由Golang教程欄目給大家Go使用websocket實現彈幕功能的方法,希望對需要的朋友有所幫助!
使用websocket協議,客戶端發送一個消息,服務端廣播到所有有效連接中。
主要思路:
1.封裝*websocket.conn,用client結構表示一個客戶端。
2.維持一個map[client]bool,表示有效的客戶端映射,用于廣播消息
3.除了處理websocket連接外,還要開啟一個廣播協程,監聽客戶端連接,斷開,發彈幕事件。
type Client struct{ wsConnect *websocket.Conn inChan chan []byte outChan chan []byte closeChan chan byte Name string //客戶的名稱 Id string //客戶id,唯一 mutex sync.Mutex // 對closeChan關閉上鎖 IsClosed bool // 防止closeChan被關閉多次 } type Message struct { EventType byte `json:"type"` // 0表示用戶發布消息;1表示用戶進入;2表示用戶退出 Name string `json:"name"` // 用戶名稱 Message string `json:"message"` // 消息內容 } clients = make(map [*util.Client] bool) // 用戶組映射 join = make(chan *util.Client, 10) // 用戶加入通道 leave = make(chan *util.Client, 10) // 用戶退出通道 message = make(chan Message, 10) // 消息通道
package main import ( "encoding/json" "fmt" "github.com/gorilla/websocket" "goGin/server/util" "net/http" ) var( upgrader = websocket.Upgrader{ // 允許跨域 CheckOrigin:func(r *http.Request) bool{ return true }, } clients = make(map [*util.Client] bool) // 用戶組映射 join = make(chan *util.Client, 10) // 用戶加入通道 leave = make(chan *util.Client, 10) // 用戶退出通道 message = make(chan Message, 10) // 消息通道 ) type Message struct { EventType byte `json:"type"` // 0表示用戶發布消息;1表示用戶進入;2表示用戶退出 Name string `json:"name"` // 用戶名稱 Message string `json:"message"` // 消息內容 } func wsHandler(w http.ResponseWriter , r *http.Request){ var( wsConn *websocket.Conn err error client *util.Client data []byte ) r.ParseForm() //返回一個map,并且賦值給r.Form name := r.Form["name"][0] id := r.Form["id"][0] if wsConn , err = upgrader.Upgrade(w,r,nil); err != nil{ return } if client , err = util.InitConnection(wsConn); err != nil{ goto ERR } client.Id = id client.Name = name // 如果用戶列表中沒有該用戶 if !clients[client] { join <- client } for { if data , err = client.ReadMessage();err != nil{ //一直讀消息,沒有消息就阻塞 goto ERR } var msg Message msg.EventType = 0 msg.Name = client.Name msg.Message = string(data) message <- msg } ERR: leave<-client//這個客戶斷開 client.Close() } func broadcaster() { for { select { // 消息通道中有消息則執行,否則堵塞 case msg := <-message: // 將數據編碼成json形式,data是[]byte類型 // json.Marshal()只會編碼結構體中公開的屬性(即大寫字母開頭的屬性) data, err := json.Marshal(msg) if err != nil { return } for client := range clients { if client.IsClosed == true { leave<-client//這個客戶斷開 continue } // fmt.Println("=======the json message is", string(data)) // 轉換成字符串類型便于查看 if client.WriteMessage(data) != nil { continue //發送失敗就跳過 } } // 有用戶加入 case client := <-join: clients[client] = true // 將用戶加入映射 // 將用戶加入消息放入消息通道 var msg Message msg.Name = client.Name msg.EventType = 1 msg.Message = fmt.Sprintf("%s join in, there are %d preson in room", client.Name, len(clients)) message <- msg // 有用戶退出 case client := <-leave: // 如果該用戶已經被刪除 if !clients[client] { break } delete(clients, client) // 將用戶從映射中刪除 // 將用戶退出消息放入消息通道 var msg Message msg.Name = client.Name msg.EventType = 2 msg.Message = fmt.Sprintf("%s leave, there are %d preson in room", client.Name, len(clients)) message <- msg } } } func main(){ go broadcaster() http.HandleFunc("/ws",wsHandler) http.ListenAndServe("0.0.0.0:7777",nil) }
package util import ( "github.com/gorilla/websocket" "sync" "errors" ) type Client struct{ wsConnect *websocket.Conn inChan chan []byte outChan chan []byte closeChan chan byte Name string //客戶的名稱 Id string //客戶id,唯一 mutex sync.Mutex // 對closeChan關閉上鎖 IsClosed bool // 防止closeChan被關閉多次 } func InitConnection(wsConn *websocket.Conn)(conn *Client ,err error){ conn = &Client{ wsConnect:wsConn, inChan: make(chan []byte,1000), outChan: make(chan []byte,1000), closeChan: make(chan byte,1), IsClosed:false, } // 啟動讀協程 go conn.readLoop(); // 啟動寫協程 go conn.writeLoop(); return } func (conn *Client)ReadMessage()(data []byte , err error){ select{ case data = <- conn.inChan: case <- conn.closeChan: err = errors.New("connection is closeed") } return } func (conn *Client)WriteMessage(data []byte)(err error){ select{ case conn.outChan <- data: case <- conn.closeChan: err = errors.New("connection is closeed") } return } func (conn *Client)Close(){ // 線程安全,可多次調用 conn.wsConnect.Close() // 利用標記,讓closeChan只關閉一次 conn.mutex.Lock() if !conn.IsClosed { close(conn.closeChan) conn.IsClosed = true } conn.mutex.Unlock() } func (conn *Client)readLoop(){ var( data []byte err error ) for{ if _, data , err = conn.wsConnect.ReadMessage(); err != nil{ goto ERR } //阻塞在這里,等待inChan有空閑位置 select{ case conn.inChan <- data: case <- conn.closeChan: // closeChan 感知 conn斷開 goto ERR } } ERR: conn.Close() } func (conn *Client)writeLoop(){ var( data []byte err error ) for{ select{ case data= <- conn.outChan: case <- conn.closeChan: goto ERR } if err = conn.wsConnect.WriteMessage(websocket.TextMessage , data); err != nil{ goto ERR } } ERR: conn.Close() }
<!DOCTYPE html> <html> <head> <title>go websocket</title> <meta charset="utf-8" /> </head> <body> <script type="text/javascript"> var wsUri ="ws://127.0.0.1:7777/ws?name=aaa&id=112"; var output; function init() { output = document.getElementById("output"); testWebSocket(); } function testWebSocket() { websocket = new WebSocket(wsUri); websocket.onopen = function(evt) { onOpen(evt) }; websocket.onclose = function(evt) { onClose(evt) }; websocket.onmessage = function(evt) { onMessage(evt) }; websocket.onerror = function(evt) { onError(evt) }; } function onOpen(evt) { writeToScreen("CONNECTED"); // doSend("WebSocket rocks"); } function onClose(evt) { writeToScreen("DISCONNECTED"); } function onMessage(evt) { writeToScreen('<span style="color: blue;">RESPONSE: '+ evt.data+'</span>'); // websocket.close(); } function onError(evt) { writeToScreen('<span style="color: red;">ERROR:</span> '+ evt.data); } function doSend(message) { // writeToScreen("SENT: " + message); websocket.send(message); } function writeToScreen(message) { var pre = document.createElement("p"); pre.style.wordWrap = "break-word"; pre.innerHTML = message; output.appendChild(pre); } window.addEventListener("load", init, false); function sendBtnClick(){ var msg = document.getElementById("input").value; doSend(msg); document.getElementById("input").value = ''; } function closeBtnClick(){ websocket.close(); } </script> <h3>WebSocket Test</h3> <input type="text" id="input"></input> <button onclick="sendBtnClick()" >send</button> <button onclick="closeBtnClick()" >close</button> <div id="output"></div> </body> </html>
關于Go使用websocket實現彈幕功能的方法就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。