【声明】
非完全原创,主要思路来自于B站视频。如果有侵权,请联系我,可以立即删除掉。
二、实现二级菜单
1、客户端登录成功时显示在线用户列表
1.1、服务端维护在线列表
想要随时获取在线的用户列表,则服务端需要维护一个数据结构来维护客户端在线信息,在本文中采用map
,以usr_id
作为key
,在检测到用户端登录时,将用户端的登录信息添加到map
中
因此,在服务端将新建一个usr_online.go
文件,里面维护一个全局map
,同时在init
函数中对其进行内存分配;在该文件中,新增了在线列表的添加/修改、删除、根据usr_id
查询在线的客户端连接、查询所有在线的客户端连接
1.2、服务端返回结构体中添加在线用户id列表
当客户端登录成功之后,现有的服务端登录返回结构体LoginReturn
只包含两个字段:错误码、错误信息。而想要客户端登录成功后立即显示在线用户列表,则必须在服务端的登录返回结构体LoginReturn
中再添加一个字段:用于表示当前在线用户usr_id
的切片
1.3、修改点
utils/msg_def.go 服务端返回结构体中添加在线用户切片
var (
UsrNotExist = LoginReturn{
403, "user not exist", nil}
UsrAlreadyExist = LoginReturn{
402, "user already exist", nil}
PwdNotMatch = LoginReturn{
401, "password not match", nil}
HandleSuccess = LoginReturn{
200, "handle success", nil}
)
type LoginReturn struct {
ErrCode int
ErrInfo string
OnlineIds []int
}
server/proc/usr_online.go 新增文件,用以维护在线用户列表
package proc
import (
"Test0/IMS/utils"
"errors"
"net"
)
//记录成功登录的客户端id和con
var onlineUsrs map[int]*net.Conn
func init() {
onlineUsrs = make(map[int]*net.Conn, 1024)
}
func AddOnlineUsr(usrId int, con *net.Conn) {
onlineUsrs[usrId] = con
}
func DelOnlineUsr(usrId int) {
delete(onlineUsrs, usrId)
}
func GetAllOnlineUsrs() map[int]*net.Conn {
return onlineUsrs
}
func GetOnlineUsrById(usrId int) (con *net.Conn, err error) {
con, ok := onlineUsrs[usrId]
if !ok {
err = errors.New(utils.UsrNotExist.ErrInfo)
}
return
}
server/proc/deal_msg.go 在服务端验证客户登录成功时,将当前客户id、连接添加到在线列表中,同时将在线列表中的用户id加到服务端返回消息结构体中
func parseMsgLogin_or_Register(con net.Conn, msg *utils.Message) (err error) {
//1. 获取客户端发送的登录消息结构体
var login utils.LoginMsg
err = json.Unmarshal([]byte(msg.MsgData), &login)
if err != nil {
fmt.Println("Server received login message unmarshal failed, err = ", err)
return
}
fmt.Println("Server received login message unmarshal success, login = ", login)
var returnMsg utils.LoginReturn
if msg.MsgType == utils.ClientLoginMsg {
//2. 验证用户名和密码,并且服务端返回的状态消息
if err = model.LoginRedisCheck(login.UsrId, login.UsrPwd); err != nil {
if err.Error() == utils.UsrNotExist.ErrInfo {
returnMsg = utils.UsrNotExist
} else if err.Error() == utils.PwdNotMatch.ErrInfo {
returnMsg = utils.PwdNotMatch
} else {
returnMsg = utils.LoginReturn{
ErrCode: 404, ErrInfo: err.Error()}
}
} else {
//将当前成功登录的客户端添加到服务端的在线列表中
onlineUsrs[login.UsrId] = &con
returnMsg = utils.HandleSuccess
for id := range onlineUsrs {
returnMsg.OnlineIds = append(returnMsg.OnlineIds, id)
}
}
} else {
//2. 注册用户
if err = model.UsrRegister(login.UsrId, login.UsrPwd); err != nil {
if err.Error() == utils.UsrAlreadyExist.ErrInfo {
returnMsg = utils.UsrAlreadyExist
} else {
returnMsg = utils.LoginReturn{
ErrCode: 404, ErrInfo: err.Error()}
}
} else {
returnMsg = utils.HandleSuccess
}
}
//3. 将服务端返回的状态消息序列化为消息结构体
buf, err := json.Marshal(returnMsg)
if err != nil {
fmt.Println("Server return status data marshal failed, err = ", err)
return
}
return utils.SendMsg(con, buf, utils.ServerReturnMsg)
}
1.4、运行结果
//客户端1
D:\WorkSpace\Golang\src\Test0\IMS>client.exe
-------------欢迎来到简易及时通讯系统-------------
1. 用户登录
2. 用户注册
3. 注销用户
4. 退出系统
请选择(1~4): 1
请输入用户ID: 1234
请输入用户密码: root
当前在线用户列表如下:
用户id 1234
-------------恭喜xxx登录成功-------------
//客户端2
D:\WorkSpace\Golang\src\Test0\IMS>client.exe
-------------欢迎来到简易及时通讯系统----------