//聊天websocket连接数据结构定义
type chat_websocket_conn struct{
user_conn *tools.WebSocketConn //已建立的客户端连接,lu_guild_account_list表id
msg_chan chan []byte //管道,向客户端写入消息
client_id *string //生成的唯一id,标识一个客户端
operator_id int64 //当前登陆用户
}
//保存每次登录的用户和websocket的连接
type chat_websocket_map struct{
map_data map[int64]chat_websocket_conn
sync.Mutex
}
func new_chat_websocket_init() *chat_websocket_map{
return &chat_websocket_map{
map_data : make(map[int64]chat_websocket_conn,0),
}
}
var websocket_conn_map = new_chat_websocket_init()
func (ws *WsChat) WsChatCreateConn(operator_id int64,w http.ResponseWriter, r *http.Request) (err error){
defer func(){
if conn != nil{
conn.Close()
}
if client_id != nil{
tools.WebSocketConnMapOnce.CloseWebSocketMap(client_id)
}
websocket_conn_map.Lock()
delete(websocket_conn_map.map_data[operator_id])
websocket_conn_map.Unlock()
}()
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil{
return
}
var (
client_id = new(string)
bytes []byte
conn_detail chat_websocket_conn
exit_chan = make(chan *string) //协程退出通知
streamer_list = make(*[]*iapi.StreamerBaseDetail,0)
)
//如果登陆者名下没有主播,关闭连接
list,err := ws.StreamerList(operator_id)
if err != nil{
logx.Error(fmt.Sprintf("tags:%+v,获取当前登陆者的主播,服务异常,关闭连接.err:%+v", ws.LogTag,err))
conn.Close()
}
if len(list) < 1{
msg_obj = new(iapi.ChatMsg)
(*msg_obj).Base = iapi.ChatMsgBase{
Act : types.WS_SYNC_FAIL,
Msg : "当前登陆者没有主播",
}
bytes,_ = pack_msg(msg_obj)
err = conn.WriteMessage(websocket.TextMessage, bytes)
if err != nil{
if !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {
logx.Error(fmt.Sprintf("tags:%+v,获取当前登陆者的主播,发送消息异常,err:%+v", ws.LogTag,err))
return
}
return
}
conn.Close()
}
//如果连接已存在,则使用已建立的
if data,ok := websocket_conn_map.map_data[operator_id];ok{
*client_id = data.client_id
goto loop
}
client_id = ws_conn_obj.CreateWebSocketConn(conn)
websocket_conn_map.Lock()
for i,count := 0,len(list); i < count; i++{
detail := list[i]
detail := &iapi.StreamerBaseDetail{
StreamerId : detail.Id,
StreamerName : detail.NickName,
StreamerAvatar : detail.Avatar,
}
fmt.Printf("数据:%+v\n",detail)
streamer_list = append(streamer_list,&detail)
}
//建立当前登录用户和连接的绑定关系
conn_detail = chat_websocket_conn{
user_conn : tools.WebSocketConnMapOnce.ConnMap[client_id],
msg_chan : make(chan []byte,chan_write_buff_limit), //消息读写管道
client_id : client_id,
streamer_list : &streamer_list,
operator_id : operator_id,
}
//为每个登陆者创建一个连接对象,保存在map中
websocket_conn_map.map_data[operator_id] = conn_detail
websocket_conn_map.Unlock()
msg_obj = new(iapi.ChatMsg)
(*msg_obj).Base = iapi.ChatMsgBase{
Act : types.WS_SYNC_SUCC,
Msg : "建立连接成功",
}
bytes, err = pack_msg(msg_obj)
if err != nil{
return
}
}
我定义了一个defer函数,其中err返回错误,则删除map里保存的websocket连接,在defer里涉及map的操作,我是加锁了,需要加锁么?
golang defer使用sync.mutex
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
3条回答 默认 最新
阿里嘎多学长 2025-10-22 21:26关注阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程
理解
你想问的是关于Go语言中
defer关键字和sync.Mutex的使用。具体来说,你想知道在使用defer时,是否可以使用sync.Mutex来保护资源。回答
在Go语言中,
defer关键字用于延迟函数的执行,直到函数返回时才执行。sync.Mutex是用于保护共享资源的互斥锁。如果你在使用
defer时,需要保护共享资源,可以使用sync.Mutex来实现。例如:func foo() { mu.Lock() defer mu.Unlock() // 使用共享资源 }在上面的例子中,
mu.Lock()用于锁定共享资源,defer mu.Unlock()用于在函数返回时解锁共享资源。但是,如果你使用
defer来保护共享资源,需要注意的是,defer会在函数返回时执行,可能会导致资源释放顺序不正确。因此,需要谨慎使用defer来保护共享资源。建议
如果你需要保护共享资源,建议使用
sync.Mutex来实现。例如:func foo() { mu.Lock() // 使用共享资源 mu.Unlock() }或者使用
defer来释放资源,但需要确保资源释放顺序正确。例如:func foo() { // 使用共享资源 defer func() { // 释放资源 }() }总结
在Go语言中,
defer关键字和sync.Mutex可以一起使用来保护共享资源。但是需要谨慎使用defer来保护共享资源,确保资源释放顺序正确。解决 无用评论 打赏 举报