【GO】当客户端断开websocket连接时,WriteMessage不会返回错误

项目场景:

在此项目中,设计有通话与任务两个模块。其中任务模块有任务为:实时记录通话时间,达到时间要求可领取奖励。
所以需要在用户与AI通话时建立websocket连接记录通话时间,每分钟对通话时间进行记录,并就该任务进度,进度完成时可领取奖励。


问题描述

在代码中创建一个websocket连接,并创建一个每分钟触发的定时器,定时修改任务进度。
WriteMessage读取不到消息时即websocket断开连接时,任务结束。

但是测试时发现,即使websocket断开连接时,
err = conn.WriteMessage(websocket.PingMessage, nil)也不会返回错误
导致不能结束任务

func RecordTime(c *gin.Context) {
	// 升级成websocket
	conn, err := up.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		logger.Errorf("up.Upgrade error:%v", err)
		return
	}

	id := c.Query("user_id")

	// 创建一个每分触发一次的定时器
	ticker := time.NewTicker(1 * time.Minute)

	defer func() {
		ticker.Stop()
		conn.Close()
	}()

	// 在for循环中等待定时器触发
	for range ticker.C {
		err = conn.WriteMessage(websocket.PingMessage, nil)
		if err != nil {
			break
		}
		var tasklist []model.PersonalTaskRecord
		err = database.Get().Raw("select task_record_id, completed_times from personal_task_record where user_id = ? and type = ? and completed_times < number", id, enum.RealTime).Scan(&tasklist).Error
		if err != nil {
			logger.Errorf("RecordTime select completed_times Error,errormsg:%s", err)
		}
		for _, record := range tasklist {
			err := database.Get().Model(&model.PersonalTaskRecord{}).Where("task_record_id = ?", record.TaskRecordID).Update("completed_times", record.CompletedTimes+1).Error
			if err != nil {
				logger.Errorf("RecordTime Update completed_times Error,errormsg:%s", err)
			}
		}
	}

}


解决方案:

在任务中添加ReadMessage(),在断开连接时,
err = conn.WriteMessage(websocket.PingMessage, nil)能正常返回错误,结束任务。

func RecordTime(c *gin.Context) {
	// 升级成websocket
	conn, err := up.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		logger.Errorf("up.Upgrade error:%v", err)
		return
	}

	id := c.Query("user_id")
	go func() {
		for {
			_, _, readerr := conn.ReadMessage()
			if readerr != nil {
				break
			}
		}
	}()

	// 创建一个每分触发一次的定时器
	ticker := time.NewTicker(1 * time.Minute)

	defer func() {
		ticker.Stop()
		conn.Close()
	}()

	// 在for循环中等待定时器触发
	for range ticker.C {
		err = conn.WriteMessage(websocket.PingMessage, nil)
		if err != nil {
			break
		}
		var tasklist []model.PersonalTaskRecord
		err = database.Get().Raw("select task_record_id, completed_times from personal_task_record where user_id = ? and type = ? and completed_times < number", id, enum.RealTime).Scan(&tasklist).Error
		if err != nil {
			logger.Errorf("RecordTime select completed_times Error,errormsg:%s", err)
		}
		for _, record := range tasklist {
			err := database.Get().Model(&model.PersonalTaskRecord{}).Where("task_record_id = ?", record.TaskRecordID).Update("completed_times", record.CompletedTimes+1).Error
			if err != nil {
				logger.Errorf("RecordTime Update completed_times Error,errormsg:%s", err)
			}
		}
	}

}


原因分析:

TODO~~~

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
如果 `websocket.WriteMessage()` 函数返回 `panic`,则说明程序发生了运行错误。这种情况通常是由于程序访问了无效的内存地址或发生了其他类型的异常。 如果程序发生 `panic`,则可以使用 Go 语言中的 `recover()` 函数进行捕获和处理。`recover()` 函数用于在程序发生 `panic` 恢复程序的控制流,并返回 `panic` 的值,如果程序没有发生 `panic`,则 `recover()` 函数返回 `nil`。 以下是一个示例程序,演示如何捕获和处理 `websocket.WriteMessage()` 函数返回 `panic` 的情况: ```go package main import ( "fmt" "net/http" "github.com/gorilla/websocket" ) var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, } func main() { http.HandleFunc("/ws", wsHandler) if err := http.ListenAndServe(":8080", nil); err != nil { fmt.Println(err) } } func wsHandler(w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { fmt.Println(err) return } defer conn.Close() for { err := conn.WriteMessage(websocket.TextMessage, []byte("Hello, World!")) if err != nil { fmt.Println(err) if p := recover(); p != nil { fmt.Println("Recovered:", p) } return } } } ``` 在上面的示例程序中,我们在 `wsHandler()` 函数中使用 `websocket.WriteMessage()` 函数向 WebSocket 连接写入消息。如果写入消息失败,程序输出错误信息,并使用 `recover()` 函数捕获和处理 `panic`。如果程序发生 `panic`,则输出 `Recovered:` 和 `panic` 的值。 注意,程序发生 `panic` ,程序立即退出当前函数,并开始向上层调用栈逐层返回,直到找到一个使用 `recover()` 函数进行恢复的函数或者程序退出。因此,在处理 `panic` ,需要确保在正确的位置进行恢复,否则可能导致程序崩溃。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李子木、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值