💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
> ### 聊天室 * main.go ~~~ package main import ( "fmt" "github.com/gorilla/websocket" "net/http" "sync" ) var cmCliConn sync.Map //所有客户端实例 //协议升级 var ConfigUpgrade = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, } func chatHandler(w http.ResponseWriter, r *http.Request) { conn, err := ConfigUpgrade.Upgrade(w, r, nil) if err != nil { fmt.Println("Websocket升级失败", "Error", err.Error()) return } client := NewChatLink(conn) cmCliConn.Store(client.conn.RemoteAddr(), client) go client.readMessage() client.writeMessage() cmCliConn.Delete(client.conn.RemoteAddr()) } func main() { //启动Http服务,绑定监听8001端口 http.HandleFunc("/chat", chatHandler) if err := http.ListenAndServe(":8001", nil); err != nil { fmt.Println("服务启动失败", "Error", err.Error()) } } ~~~ * chat\_websocket.go ~~~ package main import ( "fmt" "github.com/gorilla/websocket" "sync" ) var muChar sync.Mutex //客户端实例锁 type chatWebSocket struct { Sign string //唯一标识符 conn *websocket.Conn //客户端连接实例 writeChan chan []byte //往客户端发送数据的管道 isClose bool //连接状态 } func NewChatLink(conn *websocket.Conn) *chatWebSocket { return &chatWebSocket{ Sign: conn.RemoteAddr().String(), conn: conn, writeChan: make(chan []byte, 2048), } } func (cli *chatWebSocket) writeChannel(data []byte) { if cli.isClose { return } cli.writeChan <- data } func (cli *chatWebSocket) readMessage() { defer cli.stop() for { _, msg, err := cli.conn.ReadMessage() if err != nil { fmt.Println("读取数据失败", "Error", err.Error()) break } muChar.Lock() cmCliConn.Range(func(key, value interface{}) bool { v, _ := value.(*chatWebSocket) if !v.isClose { v.writeChan <- msg } return true }) muChar.Unlock() } } func (cli *chatWebSocket) writeMessage() { for msg := range cli.writeChan { if err := cli.conn.WriteMessage(1, msg); err != nil { fmt.Println("写入数据失败", "Error", err.Error()) break } } } func (cli *chatWebSocket) stop() { muChar.Lock() if cli.isClose { return } cli.isClose = true //关闭客户端实例 cli.conn.Close() //关闭写通道 close(cli.writeChan) muChar.Unlock() } ~~~