完成注册功能,把用户信息放到redis中
思路
1 先把user.go 放入到common/message 文件夹中
2 common/message/message.go 新增两个消息类型
3 在客户端接收用户输入
4 在client/process/userProcess.go 增加一个Register方法 ,完成请求注册
5 在server/model/userDao.go 增加了一个方法Register方法
实现功能--完成登录时返回当前在线用户
用户登录后,得到当前用户在线列表
思路分析
代码
package process
import "fmt"
//因为UserMgr 实例在服务器端有且只有一个
//因为在很多地方,都会使用的到,因此我们将其定义为一个全局变量
var (
userMgr *UserMgr
)
type UserMgr struct {
onlineUsers map[int]*UserProcess
}
//完成对UserMgr的初始化工作
func init() {
userMgr = &UserMgr{onlineUsers:make(map[int]*UserProcess,1024)}
}
//完成对onlineUsers的添加
func (this *UserMgr)AddOnlineUser(up *UserProcess) {
this.onlineUsers[up.UserId] = up
}
//删除
func (this *UserMgr)DelOnlineUser(userId int) {
delete(this.onlineUsers, userId)
}
//返回当前所有的在线的用户
func (this *UserMgr)GetAllOnlineUsers() map[int]*UserProcess {
return this.onlineUsers
}
//根据ID 返回对应的值
func (this *UserMgr)GetOnlineUserById(userId int)(up *UserProcess,err error) {
//如何从map中取出一个值
up,ok := this.onlineUsers[userId]
if !ok{ //说明 你要查找的用户当前不在线
err = fmt.Errorf("用户%d 不在线",userId)
return
}
return
}
server/process/userMgr.go
package process
import (
"awesomeProject/chatroom/client/utils"
"awesomeProject/chatroom/common/message"
"encoding/binary"
"encoding/json"
"fmt"
"net"
"os"
)
type UserProcess struct {
//暂时不需要字段。。。。
}
func (this *UserProcess)Register(usrId int,usrpwd string,usrName string) (err error) {
conn,err := net.Dial("tcp","localhost:8889")
if err!=nil{
fmt.Println("net Dail err=",err)
return
}
//延时关闭
defer conn.Close()
var mes message.Message
mes.Type = message.RegisterMesType
//3 创建一个LoginMes 结构体
var registerMes message.RegisterMes
registerMes.User.UserId = usrId
registerMes.User.UserPwd = usrpwd
registerMes.User.UserName = usrName
//将 registerMes 序列化
data,err := json.Marshal(registerMes)
if err!=nil{
fmt.Println("json marshal err=",err)
return
}
//5 把data赋给 mes.data 字段
mes.Data = string(data)
// 6 将mes 进行序列化
data,err = json.Marshal(mes)
if err!= nil{
fmt.Println("json marshal err=",err)
return
}
//创建一个Transfer实例
tf := &utils.Transfer{
Conn:conn,
}
//发送data给服务器端
err = tf.WritePkg(data)
if err != nil{
fmt.Println("注册发送信息错误 err=",err)
}
mes,err = tf.ReadPkg() //mes 就是registerMes
if err != nil{
fmt.Println("readpkg err=",err)
return
}
//将mes的data部分反序列化为 registermes
var registerResMes message.RegisterResMes
err = json.Unmarshal([]byte(mes.Data),®isterResMes)
if registerResMes.Code == 200 {
fmt.Println("注册成功 从新登陆")
os.Exit(0)
}else {
fmt.Println(registerResMes.Error)
os.Exit(0)
}
return
}
//给关联一个用户登录的方法
func (this *UserProcess)Login(usrId int,usrpwd string)(err error) {
////下一步要开始定协议
//fmt.Printf("userId= %d usrpwd=%s\n",usrId,usrpwd)
//return nil
conn,err := net.Dial("tcp","localhost:8889")
if err!=nil{
fmt.Println("net Dail err=",err)
return
}
//延时关闭
defer conn.Close()
//2 通过conn发送消息给服务
var mes message.Message
mes.Type = message.LoginMesType
//3 创建一个LoginMes 结构体
var LoginMes message.LoginMes
LoginMes.UserId = usrId
LoginMes.UserPwd = usrpwd
//4 将loginMes 序列化
data,err := json.Marshal(LoginMes)
if err!=nil{
fmt.Println("json marshal err=",err)
return
}
//5 把data赋给 mes.data 字段
mes.Data = string(data)
// 6 将mes 进行序列化
data,err = json.Marshal(mes)
if err!= nil{
fmt.Println("json marshal err=",err)
return
}
//7 这个时候data 就是我们要发送的数据
//7.1 先把data的长度发送给服务器
// 先获得到 data的长度-》转成一个表示长度的byte切片
var pkgLen uint32
pkgLen = uint32(len(data))
var buf [4]byte
binary.BigEndian.PutUint32(buf[0:4],pkgLen)
//发送长度
n,err := conn.Write(buf[:4])
if err!=nil||n != 4 {
fmt.Println("conn write err=",err)
return
}
fmt.Printf("客户端,发送消息长度ok 有%d 字节 %s",len(data),string(data))
// 发送消息本身
_,err = conn.Write(data)
if err != nil{
fmt.Println("conn write err=",err)
return
}
//这里还需要处理服务器端返回的消息
//创建一个Transfer 实例
tf := &utils.Transfer{
Conn: conn,
}
mes,err = tf.ReadPkg()
if err != nil{
fmt.Println("readpkg err=",err)
return
}
//将mes的data部分反序列化为 LoginResMes
var loginResMes message.LoginResMes
err = json.Unmarshal([]byte(mes.Data),&loginResMes)
if loginResMes.Code == 200 {
fmt.Println("用户登录成功")
//可以显示当前在线用户列表,遍历loginResmes.UserId
fmt.Println("当前在线用户列表如下")
for _,v := range loginResMes.UsersId{
//如果我们要求不显示自己在线 我们增加下边一段代码
if v == usrId{
continue
}
fmt.Println("用户ID:\t",v)
}
fmt.Println("\n\n")
//这里我们还需要启动一个协程
//该协程保持和服务器通讯 如果服务器有数据推送给客户端
//则接收并显示在客户端的终端
go serverProcessMes(conn)
// 1 显示登录成功的菜单 循环
for {
ShowMenu()
}
}else {
fmt.Println(loginResMes.Error)
}
return
}
client/process/userProcess.go
当一个新的用户上线后,其他已经登录的用户也能获取最新的在线用户列表
思路
1 当有一个用户上线后,服务器马上把维护的onlineUser map 整体推送
思路2
2 服务器有自己策略,每隔一段时间,把维护的onlineUsermap整体推送
思路3
- 当一个用户A上限后,服务器就把A用户的上线信息,推送给所有的在线用户
- 客户端也需要维护一个map,map中记录了他的好友,目前是所有人
map[int]User - 客户端和服务器的通讯通道,要依赖于serverProcessMes 协程