package main import ( "log" "net/http" "github.com/gorilla/websocket" "sync" "fmt" "strconv" "encoding/json" ) //定义我们的消息对象 type Message struct { Room_id int `json:"room_id"` Uid int `json:"uid"` Name string `json:"name"` Type string Msg string Price string //用户出价的价格 Bdlist string } //var lock sync.Mutex var lock sync.RWMutex var room = make(map[int]map[*websocket.Conn]int) //房间的详情 var price = make(map[int]int) // 房间的价格 var count = make(map[int]int) // 房间实时人数 var broadcast = make(chan Message) // 创建广播信道 //websocket设置 var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, } //创建web_socket连接 func handleConnections(w http.ResponseWriter, r *http.Request) { //将http升级到web_socket ws, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Fatal(err) } defer ws.Close() //监听消息 //room => // room_id=> // ws=>uid for { var msg Message //读取json消息,并解析为结构体 err := ws.ReadJSON(&msg) msg.Type = "join" //上锁,防止数据的冲突 lock.Lock() //存储信息到对应房间 if _, ok := room[msg.Room_id]; !ok { //判断该房间是否存在 //不存在 mm := make(map[*websocket.Conn]int) mm[ws] = msg.Uid room[msg.Room_id] = mm count[msg.Room_id] = 1 } else { //存在 room[msg.Room_id][ws] = msg.Uid //更新人数 count[msg.Room_id] += 1 } delete(room, 0) lock.Unlock() //注册到新客户缓存中 //读取失败,删除用户 if err != nil { delete(room[msg.Room_id], ws) break } //设置关闭程序(检测断开后的在线人数变化) ws.SetCloseHandler(func(code int, text string) error { count[msg.Room_id] -= 1 return nil }) //将新接收的消息发送到广播信道 broadcast <- msg } } //全局推送消息 func push() { for { //从广播频道抓取下一条消息 msg := <-broadcast //获取推送信息 msginfo := msginfo(&msg) //将其发送到当前连接的每个客户端 //上锁,保证数据 lock.RLock() //对应房间推送 for k, _ := range room[msg.Room_id] { //在本房间的进行推送 err := k.WriteJSON(msginfo) //推送失败,删除数组中的该用户状态 if err != nil { k.Close() //fmt.Println("错误的:",room[msg.Room_id][k]) delete(room[msg.Room_id], k) //fmt.Println("删除后:",room) } } //活动结束后,关闭房间 if msginfo["type"] == "end" { delete(room, msg.Room_id) delete(count, msg.Room_id) delete(price, msg.Room_id) } lock.RUnlock() } } //client发送数据组装 func msginfo(m *Message) (msg map[string]interface{}) { msg = make(map[string]interface{}) switch m.Type { case "join": msg["type"] = "join" //加入房间 msg["new_price"] = price[m.Room_id] //最新价格 msg["number"] = count[m.Room_id] //最新人数 msg["name"] = m.Name return case "start": msg["type"] = "start" msg["number"] = count[m.Room_id] msg["room_id"] = m.Room_id price[m.Room_id], _ = strconv.Atoi(m.Price) return case "change": msg["type"] = "change" msg["name"] = m.Name msg["room_id"] = m.Room_id msg["price"] = m.Price msg["bdlist"] = m.Bdlist price[m.Room_id], _ = strconv.Atoi(m.Price) case "end": msg["type"] = "end" msg["name"] = m.Name msg["room_id"] = m.Room_id msg["price"] = m.Price break } return } //结果 func errors(code int, message string) string { data := make(map[string]interface{}) data["code"] = code data["data"] = nil data["message"] = message datas, _ := json.Marshal(data) return string(datas) } //开始拍卖 func start(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json;charset=UTF-8") new_price := r.PostFormValue("new_price") room_id := r.PostFormValue("room_id") if len(room_id) > 0 { var msg Message msg.Type = "start" msg.Room_id, _ = strconv.Atoi(room_id) msg.Price = new_price //将新接收的消息发送到广播信道 broadcast <- msg fmt.Fprintln(w, errors(200, "推送成功")) } else { fmt.Fprintln(w, errors(403, "缺少参数")) } } //出价 func change(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json;charset=UTF-8") room_id := r.PostFormValue("room_id") name := r.PostFormValue("name") price := r.PostFormValue("price") bdlist := r.PostFormValue("bdlist") if len(room_id) > 0 && len(name) > 0 && len(price) > 0 && len(bdlist) > 0 { var msg Message msg.Type = "change" msg.Room_id, _ = strconv.Atoi(room_id) msg.Name = name msg.Price = price msg.Bdlist = bdlist //将新接收的消息发送到广播信道 broadcast <- msg fmt.Fprintln(w, errors(200, "推送成功")) } else { fmt.Fprintln(w, errors(403, "缺少参数")) } } //结束拍卖 func end(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json;charset=UTF-8") room_id := r.PostFormValue("room_id") name := r.PostFormValue("name") price := r.PostFormValue("price") if len(room_id) > 0 && len(name) > 0 && len(price) > 0 { var msg Message msg.Type = "end" msg.Room_id, _ = strconv.Atoi(room_id) msg.Name = name msg.Price = price //将新接收的消息发送到广播信道 broadcast <- msg fmt.Fprintln(w, errors(200, "推送成功")) } else { fmt.Fprintln(w, errors(403, "缺少参数")) } } func main() { // 配置Web的路由 http.HandleFunc("/ws", handleConnections) http.HandleFunc("/start", start) http.HandleFunc("/change", change) http.HandleFunc("/end", end) //开始监听传入聊天消息 go push() //在本地主机端口8000启动服务器并记录错误 log.Println("http server started on :88") err := http.ListenAndServe(":88", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } }
golang聊天室的搭建(实现room,群聊,指定room推送)加锁版本
猜你喜欢
转载自blog.csdn.net/feiwutudou/article/details/80948370
今日推荐
周排行