本文共 7065 字,大约阅读时间需要 23 分钟。
这一篇将继续实现go语言的多房间聊天室,第一篇实现了基本的功能,今天就继续完善,实现各种功能。
广播功能:就是游戏里的全服通告, 信息过滤:对言论信息处理,类似于不能发黄赌毒信息, 禁言功能:此处警告并禁言5分钟; 踢出群聊功能:三次不合法信息后,提醒以后并踢出群聊;由于内容较多,分成两个文件来写了;
hub.go文件:package mainimport ( "github.com/gorilla/websocket" "log" "net/http" "strings" "time")const ( writeWait = 10 * time.Second pongWait = 60 * time.Second pingPeriod = (pongWait * 9) / 10 maxMessageSize = 512)var( upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r *http.Request) bool { return true },})type connection struct { ws *websocket.Conn send chan []byte numberv int forbiddenword bool timelog int64}func (m message) readPump() { c := m.conn defer func() { h.unregister <- m c.ws.Close() }() c.ws.SetReadLimit(maxMessageSize) c.ws.SetReadDeadline(time.Now().Add(pongWait)) c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil }) for { _, msg, err := c.ws.ReadMessage() if err != nil { if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) { log.Printf("error: %v", err) } //log.Printf("error: %v", err) break } go m.Kickout(msg) }}// 信息处理,不合法言论 禁言警告,超过3次,踢出群聊;func (m message) Kickout(msg []byte) { c := m.conn // 判断是否有禁言时间,并超过5分钟禁言时间,没有超过进入禁言提醒 nowT:=int64(time.Now().Unix()) if nowT-c.timelog<300{ h.warnmsg <- m } // 不合法信息3次,判断是否有不合法信息,没有进行信息发布 if c.numberv < 3 { // 信息过滤,设置含有此字符串内字符为不合法信息, basestr := "死亡崩薨" teststr := string(msg[:]) for _, ev := range teststr { // 判断字符串中是否含有某个字符,true/false reslut := strings.Contains(basestr, string(ev)) if reslut == true { c.numberv += 1 c.forbiddenword = true // 禁言为真 // 记录禁言开始时间,禁言时间内任何信息不能发送 c.timelog = int64(time.Now().Unix()) h.warnings <- m break } } // 不禁言,消息合法 可以发送 if c.forbiddenword != true { // 设置广播消息, 所有房间内都可以收到信息;给广播消息开头加一个特定字符串为标识,当然也有其他方法; // 此例 设置以开头0为标识, 之后去掉0 ; if msg[0] == 48 { head := string("所有玩家请注意:") data := head + string(msg[1:]) m := message{ []byte(data), m.roomid, c} h.broadcastss <- m } else if msg[0] != 48 { //不是0,就是普通消息 m := message{ msg, m.roomid, c} h.broadcast <- m } } // 不合法信息超过三次,踢出群 } else { h.kickoutroom <- m log.Println("要被踢出群聊了...") c.ws.Close() // 此处关闭了踢出的连接,也可以不关闭做其他操作, }}func (c *connection) write(mt int, payload []byte) error { c.ws.SetWriteDeadline(time.Now().Add(writeWait)) return c.ws.WriteMessage(mt, payload)}func (s *message) writePump() { c := s.conn ticker := time.NewTicker(pingPeriod) defer func() { ticker.Stop() c.ws.Close() }() for { select { case message, ok := <-c.send: if !ok { c.write(websocket.CloseMessage, []byte{ }) return } if err := c.write(websocket.TextMessage, message); err != nil { return } case <-ticker.C: if err := c.write(websocket.PingMessage, []byte{ }); err != nil { return } } }}func serverWs(w http.ResponseWriter, r *http.Request) { r.ParseForm() roomid := r.Form["roomid"][0] ws, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Println(err) return } c := &connection{ send: make(chan []byte, 256), ws: ws} m := message{ nil, roomid, c} h.register <- m go m.writePump() go m.readPump()}
server.go文件:
package mainimport ( "fmt" "log" "net/http")type message struct { data []byte roomid string conn *connection}type hub struct { rooms map[string]map[*connection]bool broadcast chan message broadcastss chan message warnings chan message register chan message unregister chan message kickoutroom chan message warnmsg chan message}var h = hub{ broadcast: make(chan message), broadcastss:make(chan message), warnings: make(chan message), warnmsg: make(chan message), register: make(chan message), unregister: make(chan message), kickoutroom: make(chan message), rooms: make(map[string]map[*connection]bool),}func (h *hub) run() { for { select { case m := <-h.register: //传输链接 conns:=h.rooms[m.roomid] if conns == nil { // 链接保存到相应的房间 conns = make(map[*connection]bool) h.rooms[m.roomid] = conns fmt.Println("在线人数:==",len(conns)) fmt.Println("rooms:==",h.rooms) } h.rooms[m.roomid][m.conn] = true fmt.Println("在线人数:==",len(conns)) fmt.Println("rooms:==",h.rooms) for con := range conns { delmsg := "系统消息:欢迎新伙伴加入" + m.roomid + "聊天室!!!" data := []byte(delmsg) select { case con.send <- data: } } case m := <-h.unregister: //断开链接 conns:=h.rooms[m.roomid] if conns != nil { if _, ok := conns[m.conn]; ok { delete(conns, m.conn) //删除链接 close(m.conn.send) for con := range conns { delmsg := "系统消息:有小伙伴离开了" + m.roomid + "聊天室!欢送!!!" data := []byte(delmsg) select { case con.send <- data: } if len(conns) == 0 { // 链接都断开,删除房间 delete(h.rooms, m.roomid) } } } } case m := <-h.kickoutroom: //3次不合法信息后,被踢出群聊 conns:=h.rooms[m.roomid] notice:="由于您多次发送不合法信息,已被踢出群聊!!!" select { case m.conn.send <- []byte(notice): } if conns != nil { if _, ok := conns[m.conn]; ok { delete(conns, m.conn) close(m.conn.send) if len(conns) == 0 { delete(h.rooms, m.roomid) } } } case m := <-h.warnings: //不合法信息警告 conns:=h.rooms[m.roomid] if conns != nil { if _, ok := conns[m.conn]; ok { notice := "警告:您发布不合法信息,将禁言5分钟,三次后将被踢出群聊!!!" //starttime:= select { case m.conn.send <- []byte(notice): } } } case m := <-h.warnmsg: //禁言中提示 conns:=h.rooms[m.roomid] if conns != nil { if _, ok := conns[m.conn]; ok { notice := "您还在禁言中,暂时不能发送信息!!!" select { case m.conn.send <- []byte(notice): } } } case m := <-h.broadcast: //传输群信息/房间信息 conns := h.rooms[m.roomid] for con := range conns { if con==m.conn{ //自己发送的信息,不用再发给自己 continue } select { case con.send <- m.data: default: close(con.send) delete(conns, con) if len(conns) == 0 { delete(h.rooms, m.roomid) } } } case m := <-h.broadcastss: //传输全员广播信息 for _,conns := range h.rooms { for con:=range conns{ if con==m.conn{ //自己发送的信息,不用再发给自己 continue } select { case con.send <- m.data: default: close(con.send) delete(conns, con) if len(conns) == 0 { delete(h.rooms, m.roomid) } } } } } }}// 要运行同包下的几个文件,都要执行//go run server.go hub.gofunc main() { go h.run() http.HandleFunc("/",serverWs ) err := http.ListenAndServe(":8899", nil) if err != nil { log.Fatal("ListenAndServe: ", err) }}
ws://127.0.0.1:8899/?roomid=tang
ws://127.0.0.2:8899/?roomid=tang ws://127.0.0.3:8899/?roomid=wang ws://127.0.0.4:8899/?roomid=wang ws://127.0.0.5:8899/?roomid=wang 记录的打印信息,把请求连接加入多房间聊天室rooms,此处创建了两个房间, 以下是发送信息的显示结果: 发现有一点没有处理好,就是发的消息有的情况不需要让发信息人看到(显示), 只需要看到提醒信息…有兴趣的小伙伴可以进一步改进, 对于 ***github.com/gorilla/websocket***这个库,我了解使用的还不太多, 只是用它实现了基本功能, 大家也可以深入研究一下,转载地址:http://znqxi.baihongyu.com/