go语言多房间聊天室websocket(二)

这一篇将继续实现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 sendchan []byte numbervint forbiddenword bool timelogint64 }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 broadcastchanmessage broadcastss chanmessage warningschanmessage registerchanmessage unregisterchanmessage kickoutroom chanmessage warnmsgchanmessage}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.go func main() { go h.run() http.HandleFunc("/",serverWs ) err := http.ListenAndServe(":8899", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } }

结果: 【go语言多房间聊天室websocket(二)】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,此处创建了两个房间,
go语言多房间聊天室websocket(二)
文章图片

以下是发送信息的显示结果:
发现有一点没有处理好,就是发的消息有的情况不需要让发信息人看到(显示),
只需要看到提醒信息…有兴趣的小伙伴可以进一步改进,
对于 ***github.com/gorilla/websocket***这个库,我了解使用的还不太多, 只是用它实现了基本功能, 大家也可以深入研究一下,
go语言多房间聊天室websocket(二)
文章图片

go语言多房间聊天室websocket(二)
文章图片

go语言多房间聊天室websocket(二)
文章图片

go语言多房间聊天室websocket(二)
文章图片

go语言多房间聊天室websocket(二)
文章图片

    推荐阅读