golang中关于websocket的使用的一些高级用法

发布时间 2023-06-05 21:13:47作者: 99号的格调

很多网站都实现了“推送”功能,都会用到轮训这个技术,轮询就是每隔一段时间客户端就向服务器发送请求,来获得最新的数据。这种方式的缺点十分明显,浏览器每次发出的请求都含有比较大的header数据,浪费带宽资源。在这种背景下,HTML5定义了websocket协议,能够更好的节省服务器资源和带宽,而且可以实时的进行通信。

Golang官方推荐的一个包:github.com/gorilla/websocket

使用方法:go get github.com/gorilla/websocket

需求:通过websocket发来的数据在前端展示出来

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/gorilla/websocket"
)

type Message struct {
	Name string `json:"name"`
	Mess string `json:"mess"`
}

var clients = make(map[*websocket.Conn]bool)
var broadcast = make(chan *Message)
var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	content, err := ioutil.ReadFile("index.html")
	if err != nil {
		fmt.Println("could not find index.html")
	}
	fmt.Fprintf(w, "%s", content)
}
func writer(mess *Message) {
	broadcast <- mess
}
func messHandler(w http.ResponseWriter, r *http.Request) {
	var mess Message
	if err := json.NewDecoder(r.Body).Decode(&mess); err != nil {
		log.Printf("Error:%s", err)
		http.Error(w, "Bad Request", http.StatusTeapot)
		return
	}
	defer r.Body.Close()
	go writer(&mess)

}

func wsHandler(w http.ResponseWriter, r *http.Request) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Fatal(err)
	}
	clients[ws] = true
}

func echo() {
	for {
		mess := <-broadcast
		hismess := fmt.Sprintf("%s : %s \n", mess.Name, mess.Mess)
		fmt.Println(hismess)
		for client := range clients {
			err := client.WriteMessage(websocket.TextMessage, []byte(hismess))
			if err != nil {
				log.Printf("websocket error:%s", err)
				client.Close()
				delete(clients, client)
			}
		}
	}
}

func main() {
	http.HandleFunc("/", rootHandler)
	http.HandleFunc("/chat", messHandler)
	http.HandleFunc("/ws", wsHandler)
	go echo()
	panic(http.ListenAndServe(":7788", nil))
}

然后通过本地终端去发送请求,这里没有专门去写服务端代码

 curl -H "Accept:application/json" -XPOST -d '{"name":"KOl","mess":"this is a test data"}' localhost:7788/chat

下面给出前端逻辑


<body>
    <h1>Chat/History</h1>
    <div id="mess"></div>
    <script type="text/javascript">
        var mess = document.getElementById("mess");
        var exampleSocket = new WebSocket("ws://"+location.host+"/ws")
        var update = function(){
            exampleSocket.onmessage = function(event){
                var chat = event.data;
                var br = document.createElement("br");
                mess.textContent = mess.textContent+chat.toString();
                mess.appendChild(br);
            }
        };
        window.setTimeout(update);
    </script>
</body>

这个需求引入了channle,网络,map,goroutine相关的内容,可以好好品味。