showliuzp 2025-10-23 14:32 采纳率: 84.3%
浏览 3

golang select退出


func (ws *WsChat) WsChatMsgWrite(operator_id int64,conn *websocket.Conn,exit_chan chan int64){
    //conn.SetWriteDeadline(ws_write_timeout_limit)
    var (
        chat_conn *chat_websocket_conn
        ok bool
        )

    if chat_conn,ok = websocket_conn_map.map_data[operator_id];!ok{
        return
    }

    //如退出,向exit_chan发出消息,删除该client_id对应的websocket
    defer func(){
        exit_chan <- operator_id
    }()

    for{

        select{
            case data,ok := <-(*chat_conn).msg_chan:
            if !ok{
                return
            }

            if err := tools.WebSocketConnOnce.WriteMsg((*chat_conn).client_id,&data); err != nil {
                if !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {
                    logx.Error(fmt.Sprintf("tags:%+v,向客户端发送数据,连接非正常关闭,data:%+s,err:%+v",ws.LogTag,data,err))
                }

                return
            }

            default:
                //ping/pong处理
                conn.SetPingHandler(func(appData string) error {
                    return conn.WriteControl(websocket.PongMessage, []byte("pong"), time.Now().Add(time.Second))
                })

                //收到关闭帧退出,defer函数会处理
                conn.SetCloseHandler(func(code int, text string) error {
                    return nil
                })
        }
    }
}


我在做一个websocket功能,conn唯一标识一个socket连接,如果收到ping或者关闭帧,该协程退出,但我用postman关闭websocket后,陷入死循环,应该怎么处理?
  • 写回答

2条回答 默认 最新

  • 紫雾凌寒 新星创作者: 人工智能技术领域 2025-10-23 14:33
    关注

    让 “紫雾凌寒” 来帮你回答,本回答结合 DeepSeek

    如果还有问题,请评论或点击头像私信,如果有帮助到您, 请关注、采纳、点赞

    1. 关键点分析
      - 从提供的代码片段来看,定义了一个名为WsChatMsgWrite的方法,其中包含了与WebSocket连接相关的操作以及一个退出通道exit_chan。但代码不完整,不太明确具体需求,不过推测可能是要在这个方法中实现根据exit_chan的信号来优雅地退出相关操作,比如关闭WebSocket连接等。
    2. 解决方案
      - 在select语句中监听exit_chan。当接收到exit_chan中的值时,执行相应的清理和退出操作。
      - 假设这里要关闭WebSocket连接并进行一些资源清理工作,示例代码如下:
    func (ws *WsChat) WsChatMsgWrite(operator_id int64, conn *websocket.Conn, exit_chan chan int64) {
        for {
            select {
            case <-exit_chan:
                // 关闭WebSocket连接
                err := conn.Close()
                if err!= nil {
                    log.Println("Error closing WebSocket connection:", err)
                }
                // 进行其他资源清理工作,比如关闭相关的数据库连接等
                //...
                return
            default:
                // 正常的业务逻辑,比如发送消息等
                // 示例:发送消息到WebSocket
                err := conn.WriteMessage(websocket.TextMessage, []byte("Hello, World!"))
                if err!= nil {
                    log.Println("Error writing to WebSocket:", err)
                    return
                }
            }
        }
    }
    
    1. 多种解决方案及优缺点
      - 方案一:使用select监听通道
      • 优点:简洁明了,能够很好地处理异步事件,当exit_chan有信号时可以及时响应并进行清理退出操作。
      • 缺点:如果没有其他需要监听的通道,单纯为了监听退出通道,可能会显得有些冗余。
      • 方案二:在循环中检查全局变量
      • 优点:可以避免使用通道,代码结构上可能会更简洁一些。
      • 缺点:需要额外定义和维护一个全局变量来表示是否退出,并且在多线程环境下需要注意变量的同步问题,容易引入竞态条件。示例代码如下:
    var shouldExit bool
    
    func (ws *WsChat) WsChatMsgWrite(operator_id int64, conn *websocket.Conn) {
        while!shouldExit {
            // 正常的业务逻辑,比如发送消息等
            // 示例:发送消息到WebSocket
            err := conn.WriteMessage(websocket.TextMessage, []byte("Hello, World!"))
            if err!= nil {
                log.Println("Error writing to WebSocket:", err)
                return
            }
        }
        // 关闭WebSocket连接
        err := conn.Close() 
        if err!= nil {
            log.Println("Error closing WebSocket connection:", err)
        }
        // 进行其他资源清理工作,比如关闭相关的数据库连接等
        //...
    }
    
    1. 总结
      - 对于在Go语言中实现基于通道的退出机制,select监听通道是一种常用且有效的方法。它能够方便地处理异步事件,确保在接收到退出信号时能够正确地进行清理和退出操作。在实际应用中,应根据具体需求选择合适的方法来实现优雅退出功能。

    请注意,上述代码中的log.Println是简单的日志记录示例,实际应用中可根据需求替换为更完善的日志库。同时,完整的代码可能需要更多的上下文信息来确保正确性和健壮性。

    希望以上解答对您有所帮助。如果您有任何疑问,欢迎在评论区提出。

    评论

报告相同问题?

问题事件

  • 创建了问题 10月23日