ToB企服应用市场:ToB评测及商务社交产业平台
标题:
[go-websocket 搭建一对一,一对多的聊天室] 第二篇:websocket间的通信
[打印本页]
作者:
海哥
时间:
2022-8-29 00:08
标题:
[go-websocket 搭建一对一,一对多的聊天室] 第二篇:websocket间的通信
源码地址
https://gitee.com/bin-0821/chat-room-demo-go-websocket
关于websocket,上一篇文章讲述了如何通过websocket进行服务端与客户端的通信,本篇将会带领大家把各个websocket进行相互通信,在开始之前,请确保有理解
1 go的通道
2 go的线程
3 gin基础
事实上,websocket与websocket之间是无法进行直接相互通信的,需要我们将数据接收后,发送给另一个websocket链接,可以理解为
conn1.ReadJson(&data)
conn2.WriteJson(data)
复制代码
而建立一个类似微信聊天一样的,能进行多群聊,一对多,一对一的聊天,需要对websocket进行管理,本篇文章的重点便是如何管理好所有用户的websocket连接,主要有以下方面
1,一个根据业务进行设计的数据结构
2,用户上下线后conn的处理
3,用户发送信息的群发或单发
首先,要搞清楚我们在做什么,聊天室要实现的功能类似微信
a,b,c三人,1,2,3 三个聊天室
人员 加入的聊天室
a 1,2,3
b 1,2
c 1
复制代码
a在1发送信息,全部人都能收到
a在2发送信息,c收不到,以此类推
a可以与c单独发送信息,接收方不在线时,系统能正常运行
1. 目录结构
相比上篇文章 多了manage_socket_conn,service两个模块,重点在于多了manage_socket_conn模块中
D:.
│ go.mod
│ go.sum
│ main.go
│ msg.json
├─api
│ socket_conn.go
├─manage_socket_conn //用户的websocket管理模块
│ char_room_thread.go //线程 主要负责对信息的群发
│ room_set.go //聊天室房间管理,房间的创建,销毁 存储房间内的用户id
│ user_set.go //用户websocket链接管理,信息的发送,存储所有在线的webscoket链接,用户上下线
├─middleware
│ Cros.go
├─model
│ socket_msg_form_front.go
│ to_front.go
├─route
│ route.go
└─service
chat_room.go //数据层,模拟用户加入了那些聊天室
复制代码
2. 代码内容
user_set.go
package manage_socket_conn
import (
"WebSocketDemo/model"
"errors"
"fmt"
"github.com/gorilla/websocket"
"sync"
)
func init() {
GetUserSet()
}
//用户map 用来存储每个在线的用户id与对应的conn
type userSet struct {
// 用户链接集 用户id => 链接对象
users map[int]*websocket.Conn
lock sync.Mutex
once sync.Once
}
var us = new(userSet)
// 单例模式
func GetUserSet() *userSet {
us.once.Do(func() {
us.users = make(map[int]*websocket.Conn)
us.users[-1] = nil
us.lock = sync.Mutex{}
})
return us
}
// 用户创建发起websocket连接
// join_type 加入模式
// 1 正常加入 占线无法加入
// 2 强制加入 即踢下线前者
func (u *userSet) ConnConnect(user_id, join_type int, conn *websocket.Conn) (int, error) {
u.lock.Lock()
defer u.lock.Unlock()
if join_type == 1 {
// 用户id是否已经在线
if _, ok := u.users[user_id]; ok {
return 1, errors.New("该账号已被登陆")
}
} else if join_type == 2 {
// 如果原用户id 已经存在map内 进行销毁挤出
if conn2, ok := u.users[user_id]; ok {
err := conn2.Close()
if err != nil {
fmt.Println(err)
}
delete(u.users, user_id)
}
// 重新加入
u.users[user_id] = conn
}
return -1, nil
}
// 链接断开
func (u *userSet) ConnDisconnect(user_id int, conn *websocket.Conn) error {
u.lock.Lock()
defer u.lock.Unlock()
if conn2, ok := u.users[user_id]; ok {
if conn == conn2 {
delete(u.users, user_id)
}
} else {
// Log 不存在的链接申请断开
}
return nil
}
// 对单个链接发送信息
func (u *userSet) SendMsgByUid(user_id int, msg interface{}) error {
var err error
if conn, ok := u.users[user_id]; ok {
err = conn.WriteJSON(msg)
} else {
err = errors.New("不存在的链接")
}
return err
}
// 对多个连接发送信息
func (u *userSet) SendMsgByUidList(user_id_list []int, msg interface{}) (id_list []int, err_list []error) {
for _, user_id := range user_id_list {
// 这里判断用户是否自己,是自己就跳过
c := msg.(model.ChatMsg)
if c.ChatMsgType == 1 {
if (c.Data["form_user_id"].(int)) == user_id {
continue
}
}
if conn, ok := u.users[user_id]; ok {
err := conn.WriteJSON(msg)
if err != nil {
id_list = append(id_list, user_id)
err_list = append(err_list, err)
}
} else {
id_list = append(id_list, user_id)
err_list = append(err_list, errors.New("不存在的链接"))
}
}
return
}
复制代码
room_set.go
[code]package manage_socket_connimport ( "sync")//群map 用来存储每个群在线的用户idtype roomSet struct { // 群id 群内的用户id rooms map[int]map[int]struct{} lock sync.Mutex once sync.Once}var rs = new(roomSet)// 单例func GetRoomSet() *roomSet{ rs.once.Do(func() { rs.rooms = make(map[int]map[int]struct{}) rs.lock = sync.Mutex{} }) return rs}// 向用户发送func (r *roomSet)SendMsgToUserList (r_id int ,msg interface{}){ userS := GetUserSet() r.lock.Lock() defer r.lock.Unlock() var user_id_list []int for key, _ := range r.rooms[r_id] { user_id_list = append(user_id_list, key) } userS.SendMsgByUidList(user_id_list,msg)}// 用户下线/退群 退出聊天室链接集合func (r *roomSet) UserQuitRooms(room_id_list []int ,user_id int) { r.lock.Lock() defer r.lock.Unlock() for _, room_id := range room_id_list { if v ,ok := r.rooms[room_id];ok { delete(v,user_id) // 房间没人就销毁 if len(r.rooms[room_id])
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4