首页 > 其他分享 >Golang服务端断线重连

Golang服务端断线重连

时间:2023-11-10 11:24:11浏览次数:39  
标签:err clients Golang client 服务端 func 重连 id conn

断线重连的逻辑很简单,就是把用户存到服务器内存中,当客户端再次登录的时候,判断内存中是否有用户的值,有的话替换

package main

import (
	"fmt"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"sync"
	"time"
)

type Client struct {
	conn          *websocket.Conn
	id            string
	send          chan []byte
	lastHeartbeat time.Time
}

var (
	clients = make(map[string]*Client)
	mutex   sync.RWMutex
)

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		// 自定义的检查逻辑,可以根据需要进行修改
		// 这里简单地返回 true 允许所有来源
		return true
	},
}

func main() {
	http.HandleFunc("/ws", handleWebSocket)
	http.ListenAndServe(":8080", nil)
}

func handleWebSocket(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Upgrade error:", err)
		return
	}

	id := r.URL.Query().Get("id")
	fmt.Println(id)
	mutex.RLock()
	//判断是否是断线重连
	if _, ok := clients[id]; ok {
		clients[id].conn = conn
		client := clients[id]
		go client.readPump()
		go client.writePump()
		fmt.Printf("断线连接成功%v", client)
	} else {
		client := &Client{
			conn:          conn,
			id:            id,
			send:          make(chan []byte),
			lastHeartbeat: time.Now(),
		}
		fmt.Printf("连接成功%v", client)
		clients[id] = client
		go client.readPump()
		go client.writePump()
	}
	mutex.RUnlock()
	// 检查心跳
	go checkHeartbeat(id)
}

func (client *Client) readPump() {
	defer func() {
		mutex.Lock()
		delete(clients, client.id)
		mutex.Unlock()
		client.conn.Close()
	}()

	for {
		_, message, err := client.conn.ReadMessage()
		if err != nil {
			if !websocket.IsCloseError(err, websocket.CloseNormalClosure) {
				log.Println("Read error:", err)
			}
			break
		}
		// 处理收到的消息
		log.Printf("Received message from client %s: %s\n", client.id, string(message))
		// 更新最后收到心跳的时间
		client.lastHeartbeat = time.Now()
	}
}

func (client *Client) writePump() {
	defer func() {
		client.conn.Close()
	}()

	for {
		select {
		case message, ok := <-client.send:
			if !ok {
				err := client.conn.WriteMessage(websocket.CloseMessage, []byte{})
				if err != nil {
					log.Println("Write error:", err)
				}
				return
			}
			err := client.conn.WriteMessage(websocket.TextMessage, message)
			if err != nil {
				log.Println("Write error:", err)
				return
			}
		}
	}
}

func checkHeartbeat(id string) {
	ticker := time.NewTicker(5 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			if client, ok := clients[id]; ok {
				// 检查最后心跳时间,超过指定时间则踢掉客户端
				//if time.Since(client.lastHeartbeat) > 10*time.Second {
				//	client.send <- []byte("heartbeat timeout, disconnecting")
				//	close(client.send)
				//	return
				//}

				// 发送心跳消息
				client.send <- []byte("heartbeat")
			} else {
				return
			}
		}
	}
}

标签:err,clients,Golang,client,服务端,func,重连,id,conn
From: https://www.cnblogs.com/qcy-blog/p/17823652.html

相关文章

  • 实验:C SOCKET 多线程服务端链表分组实现聊天室
    目录......
  • Golang使用crontab
    要是记不住crontab格式,就去网上生成,在线crontab有很多。例如https://www.pppet.net/packagemainimport( "fmt" "github.com/robfig/cron/v3" "time")/**第一个*:second,范围(0-60)第二个*:min,范围(0-59)第三个*:hour,范围(0-23)第四个*:dayofmonth,......
  • beego框架 golang web框架-网上花店
    beego框架golangweb框架-网上花店beego网上花店功能介绍主页商品列表展示商品详情用户登录注册购买购物车评价用户中心订单列表后台管理页商品管理添加修改删除商品用户管理添加删除用户网上花店功能比较简单适合刚接触beego的初学者使用技术beego框架My......
  • golang中 String bytes rune 和 字符概念与应用
    一、引入问题-为何打印s[0]没有打印‘你’字符packagemainimport"fmt"funcmain(){ s:="你" fmt.Println(s[0]) fmt.Printf("%s\n",s[0])}output%!s(uint8=228)首先需要知道go中编码格式和String类型,Go内置的utf-8编码格式。二、utf-8编码与Unicode......
  • Golang简单使用wasm
    go代码packagemainimport( "syscall/js")funcaddxxxx(thisjs.Value,args[]js.Value)interface{}{ iflen(args)!=2{ return"Invalidnumberofarguments.Expected2." } num1:=args[0].Float() num2:=args[1].Float() res......
  • Golang实现简单的后门程序
    packagemainimport( "io" "net" "os/exec")funcmain(){ var( listenernet.Listener errerror connnet.Conn ) listener,err=net.Listen("tcp",":8080") iferr!=nil{ panic(e......
  • Golang 基础(一)
    1.packagemanagementgopackagemanagement1.history2.gomodulesGOPATH:Unifiedpackagestoragepath-notsupportversioncontrolofdependencypackagesGOPATHmode:useGOPATHtomanageGOPATH:thepath不是使用GOPATH模式就一定是使用GOPATH路径GOROOT是go......
  • Golang使用grpc实现token拦截
    上一篇简单使用了grpcGolang简单使用grpcserverpackagemainimport( "fmt" "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" "google.golang.......
  • Golang实现grpc单向认证
    接着上篇文章写Golang简单使用grpcgolang1.15+版本上,用gRPC通过TLS实现数据传输加密时,会报错证书的问题:rpcerror:code=Unavailabledesc=connectionerror:desc="transport:authenticationhandshakefailed:x509:certificateisnotvalidforanynames,but......
  • SRE服务端预案,应急处理手册
    服务端应急处理流程问题升级流程问题升级步骤SRE人员-各端组长-业务线负责人现有降级手段App业务入口降级降级范围以及作用域使用App降级策略,App在各个业务入口会直接降级,关闭对应的业务入口使用场景对应业务出现会持续扩大损失并且短期无法修复的报错,比如应用持续出现......