前端地址:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Websocket</title>
</head>
<body>
<h1>字符串转换大写</h1>
<form>
<p>
字符串: <input id="content" type="text" placeholder="输入要转换的字符串">
</p>
</form>
<label id="result">结果为:</label><br><br>
<button onclick="send()">转换</button>
<script type="text/javascript">
var sock = null;
createWebSocket();
// if(!window.localStorage){
// console.log(333)
// alert("浏览器不支持localstorage!");
// }
// var sock = localStorage.getItem("ws");
// if (!sock) {
// localStorage.setItem("ws",sock);
// }
sock.onmessage = function(e) {
var result = document.getElementById('result');
result.innerHTML = "结果为:" + e.data;
}
sock.onerror = function (e) {
alert('llws连接错误: ')
console.log(e)
};
sock.onclose = function (e) {
alert('websocket 断开: ' + e.code + ' ' + e.reason + ' ' + e.wasClean)
console.log(e)
}
window.onbeforeunload = function() {
sock.close();
}
function send() {
var msg = document.getElementById('content').value;
sock.send(msg);
}
function createWebSocket() {
try{
if('WebSocket' in window){
sock = new WebSocket("ws://127.0.0.1:9999/ws");
}
}catch(e){
alert(e.reason)
}
}
</script>
</body>
</html>
后端golang代码:
package main
import (
"fmt"
"log"
"net/http"
"strconv"
"time"
"github.com/gorilla/websocket"
)
//用户连接具体设置类
type WskCon struct {
Name string //生成用户名
Con *websocket.Conn //定义用户连接客户端
OnlineTime int64 //定义用户在线时间啊in
}
//用户类
type Users struct {
cons []WskCon //连接数据集
HeartTime int64 //
ChnCon chan *websocket.Conn //协程连接
}
var u *Users
func init() {
//初始化用户类
s := &Users{HeartTime: 60}
u = s
}
func main() {
http.HandleFunc("/ws", handleWebSocket)
http.HandleFunc("/all", handleAll)
err := http.ListenAndServe(":9999", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
//群发信息
func handleAll(w http.ResponseWriter, r *http.Request) {
for _,ws:= range u.cons {
err := ws.Con.WriteMessage(websocket.TextMessage, []byte("群发信息了"))
fmt.Println(err)
}
fmt.Println("所有连接",u.cons)
}
//切片元素移除
func removeSlice(slice []WskCon, index int) []WskCon{
return append(slice[:index],slice[index+1:]...)
}
//心跳检测
func heartCheck() {
ticker := time.NewTicker(3*time.Second)
defer ticker.Stop()
for {
select {
case t := <-ticker.C:
fmt.Println("Current time: ", t, u.cons)
currTime := time.Now().Unix()
for k, v := range u.cons {
//超过心跳时间,自动剔除此数据,超时60s
if (currTime - v.OnlineTime) > u.HeartTime {
//移除退出的连接
u.cons = removeSlice(u.cons, k)
v.Con.Close()
}
}
}
}
}
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
// 升级 HTTP 连接为 WebSocket 连接
upgrader := websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
// 解决跨域问题
CheckOrigin: func(r *http.Request) bool {
return true
},
}
//检查连接数
conn, err := upgrader.Upgrade(w, r, nil)
if len(u.cons) >= 2 {
conn.WriteMessage(websocket.TextMessage, []byte("连接人数太多,请稍后重试"))
conn.Close()
return
}
conn.WriteMessage(websocket.TextMessage, []byte("老铁,我连接上了"))
//添加连接到集合
name := strconv.FormatInt(time.Now().Unix(),10)
u.cons = append(u.cons, WskCon{
Name: name,
Con: conn,
OnlineTime: time.Now().Unix(),
})
fmt.Println("all con->",u.cons)
if err != nil {
log.Println(err)
return
}
defer conn.Close()
//检测心跳
go heartCheck()
//chans := make(chan *websocket.Conn, 2000)
// 循环读取 WebSocket 消息
for {
_, message, err := conn.ReadMessage()
if err != nil {
log.Println(err)
break
}
fmt.Println("收到消息:", string(message))
//发送消息,更新在线时间
for k,v:= range u.cons{
if name == v.Name {
u.cons[k].OnlineTime = time.Now().Unix()
}
}
// 发送消息
err = conn.WriteMessage(websocket.TextMessage, message)
if err != nil {
log.Println(err)
break
}
}
}