GO语言综合项目
包含:
1:GO语言基础知识
2:TCP-Socket网络编程
3:Redis数据库
已实现:
登录
查看在线用户
群聊
私聊(未实现)
历史消息(未实现)
注册
退出
整体结构
客户端client
1 package main 2 3 import ( 4 "ChatRoom/client/process" 5 "fmt" 6 "os" 7 ) 8 9 var ( 10 userID int 11 userPsw string 12 userName string 13 ) 14 15 func main() { 16 var key int 17 for { 18 fmt.Println("------/ 多人互动聊天系统 /------") 19 fmt.Printf("1 登录系统 2 注册账户 3 退出系统 请输入(1-3)数字进行操作 ") 20 fmt.Scanln(&key) 21 switch key { 22 case 1: 23 fmt.Println("登录聊天室") 24 fmt.Println("请输入ID号") 25 fmt.Scanln(&userID) 26 fmt.Println("请输入密码") 27 fmt.Scanln(&userPsw) 28 29 //验证成功后 30 /*mvs后,使用process下的UserProcess结构体实例 31 调用绑定的Login登录方法 32 */ 33 up := &process.UserProcess{} 34 up.Login(userID, userPsw) 35 36 case 2: 37 //注册界面 38 fmt.Println("请输入 ID号") 39 fmt.Scanln(&userID) 40 fmt.Println("请输入 密码") 41 fmt.Scanln(&userPsw) 42 fmt.Println("请输入 聊天昵称") 43 fmt.Scanln(&userName) 44 //调用UserProcess完成注册 45 up := &process.UserProcess{} 46 up.Register(userID, userPsw, userName) 47 case 3: 48 os.Exit(1) 49 default: 50 fmt.Println("输入有误,请重新输入(1-3)") 51 } 52 } 53 }
1 package model 2 3 import ( 4 "ChatRoom/conmon/message" 5 "net" 6 ) 7 8 /* 9 CurrentUser 当前用户 10 11 Conn 连接 12 13 message.User 用户信息 14 */ 15 type CurrentUser struct { 16 Conn net.Conn 17 message.User 18 }
1 package process 2 3 import ( 4 "ChatRoom/client/utils" 5 "ChatRoom/conmon/message" 6 "encoding/json" 7 "fmt" 8 "net" 9 "os" 10 ) 11 12 //ShouMenu 显示登录后的界面菜单 13 func ShouMenu() { 14 for { 15 16 var inputKey int 17 var content string 18 19 /*因为会经常用到SmsProcess,所以我们定义在Switch外部,减少创建实例化的次数*/ 20 SmsProcess := &SmsProcess{} 21 fmt.Println( 22 ` 23 1 显示在线用户 24 2 聊天 25 3 查看消息 26 4 退出系统 27 28 请输入(1-4)数字进行操作! 29 30 `) 31 fmt.Scanln(&inputKey) 32 switch inputKey { 33 case 1: 34 35 /*调用显示在线用户的方法*/ 36 ShowOnLineUser() 37 38 case 2: 39 40 fmt.Println("请输入发送内容...") 41 fmt.Scanln(&content) 42 /*调用SmsProcess的发送消息方法*/ 43 SmsProcess.EnterMsg(content) 44 45 case 3: 46 fmt.Println("查看历史消息") 47 case 4: 48 fmt.Println("选择了退出系统...") 49 os.Exit(1) 50 default: 51 fmt.Println("输入有误,请输入(1-4)") 52 } 53 } 54 } 55 56 //KeepConnection 保持客户端 与 服务端 之间的通讯,显示服务端推送的信息给客户端显示 57 func KeepConnection(conn net.Conn) { 58 //创建Tranfer实例,循环读取服务器发送的消息 59 tf := &utils.Transfer{ 60 Conn: conn, 61 } 62 for { 63 fmt.Println("") 64 msg, err := tf.ReadPkg() 65 if err != nil { 66 fmt.Println("客户端读取服务器信息错误! ", err) 67 } 68 /*读取到消息,做进一步处理...*/ 69 switch msg.Type { 70 case message.PushUserStatusMsgType: 71 //有人上线了 72 73 /*先实例化PushUserStatusMsg*/ 74 var pushUserStatusMsg message.PushUserStatusMsg 75 76 /* 将 msg 反序列化*/ 77 json.Unmarshal([]byte(msg.Data), &pushUserStatusMsg) 78 79 /* 将用户信息保存到 客户端维护的 map集合中 */ 80 UpdateUserStatus(&pushUserStatusMsg) 81 82 case message.SmsMsgType: 83 //有群发消息 84 85 PinrtGroupMessage(&msg) 86 default: 87 fmt.Printf("返回的消息类型,暂时无法处理.. ") 88 } 89 90 } 91 }
1 package process 2 3 import ( 4 "ChatRoom/conmon/message" 5 "encoding/json" 6 "fmt" 7 ) 8 9 //PinrtGroupMessage 输出群发消息 10 func PinrtGroupMessage(msg *message.Message) { 11 /*反序列化msg.data*/ 12 var smsmsg message.SmsMsg 13 err := json.Unmarshal([]byte(msg.Data), &smsmsg) 14 if err != nil { 15 fmt.Println("反序列化 msg.data 失败...") 16 return 17 } 18 19 //显示信息 20 talking := fmt.Sprintf("ID:%v %v", smsmsg.UserID, smsmsg.Content) 21 fmt.Println(talking) 22 fmt.Println() 23 }
1 package process 2 3 import ( 4 "ChatRoom/client/utils" 5 "ChatRoom/conmon/message" 6 "encoding/json" 7 "fmt" 8 ) 9 10 //SmsProcess 发送消息结构体 11 type SmsProcess struct { 12 } 13 14 //EnterMsg 发送消息 15 func (sp *SmsProcess) EnterMsg(content string) (err error) { 16 /* 1 创建一个父类信息结构体实例化对象 */ 17 var msg message.Message 18 msg.Type = message.SmsMsgType 19 20 /* 2 创建一个 子类信息 结构体实例化对象 */ 21 var smsMsg message.SmsMsg 22 smsMsg.Content = content 23 smsMsg.UserID = cu.UserID 24 smsMsg.UserStatus = cu.UserStatus 25 26 /*3 将 smsMsg 序列化 */ 27 data, err := json.Marshal(smsMsg) 28 if err != nil { 29 fmt.Println("smsMsg 序列化失败!") 30 return 31 } 32 33 /*4 将data 复制给 msg.Data */ 34 msg.Data = string(data) 35 36 /*5 将 msg 序列化 */ 37 data, err = json.Marshal(msg) 38 if err != nil { 39 fmt.Println("msg 序列化 失败!") 40 return 41 } 42 43 /*6 发送消息*/ 44 tf := &utils.Transfer{ 45 Conn: cu.Conn, 46 } 47 48 err = tf.WritePkg(data) 49 if err != nil { 50 fmt.Println("发送信息失败!") 51 return 52 } 53 return 54 }
1 package process 2 3 import ( 4 "ChatRoom/client/model" 5 "ChatRoom/conmon/message" 6 "fmt" 7 ) 8 9 //OnLineUsers 客户端维护的map 10 var OnLineUsers map[int]*message.User = make(map[int]*message.User, 10) 11 12 //CurrentUser 当前用户结构体 13 var cu model.CurrentUser 14 15 //ShowOnLineUser 在客户端显示所有的在线用户 16 func ShowOnLineUser() { 17 fmt.Println("↓当前在线用户:↓") 18 for id := range OnLineUsers { 19 fmt.Printf("id: %v ", id) 20 } 21 } 22 23 //UpdateUserStatus 处理服务器返回的 PushUserStatusMsg信息 24 func UpdateUserStatus(pushUserStatusMsg *message.PushUserStatusMsg) { 25 26 user, ok := OnLineUsers[pushUserStatusMsg.UserID] 27 if !ok { 28 user = &message.User{ 29 UserID: pushUserStatusMsg.UserID, 30 } 31 } 32 33 user.UserStatus = pushUserStatusMsg.Status 34 OnLineUsers[pushUserStatusMsg.UserID] = user 35 36 /* 调用显示在线用户方法 */ 37 ShowOnLineUser() 38 }
1 package process 2 3 import ( 4 "ChatRoom/client/utils" 5 "ChatRoom/conmon/message" 6 "encoding/binary" 7 "encoding/json" 8 "fmt" 9 "net" 10 "os" 11 ) 12 13 //UserProcess 用户处理器 结构体 14 type UserProcess struct { 15 } 16 17 //Register 注册聊天账户 18 func (up *UserProcess) Register(userID int, userPsw string, userName string) (err error) { 19 //1 连接服务器 20 conn, err := net.Dial("tcp", "127.0.0.1:9000") 21 if err != nil { 22 fmt.Println("连接服务器失败 ", err) 23 return 24 } 25 26 //延迟关闭数据库通道 27 defer conn.Close() 28 29 //2 连接服务端成功,准备发送数据 30 var msg message.Message 31 msg.Type = message.RegisterMsgType 32 33 //3 创建 RegisterMsg 结构体 34 var registerMsg message.RegisterMsg 35 registerMsg.User.UserID = userID 36 registerMsg.User.UserPsw = userPsw 37 registerMsg.User.UserName = userName 38 39 //4 将registerMsg 结构体序列化为json 40 data, err := json.Marshal(registerMsg) 41 if err != nil { 42 fmt.Println("序列化失败! ", err) 43 return 44 } 45 46 //5 将data数据 赋值给 msg.Data 47 msg.Data = string(data) 48 49 //6 将msg 序列化 为json 50 data, err = json.Marshal(msg) 51 if err != nil { 52 fmt.Println("序列化失败! ", err) 53 return 54 } 55 56 //7 创建一个Transfer实例 57 58 tf := &utils.Transfer{ 59 Conn: conn, 60 } 61 //7.1 发送dada给服务器 62 err = tf.WritePkg(data) 63 if err != nil { 64 fmt.Println("客户端:注册时发送数据错误! ", err) 65 os.Exit(0) 66 67 } 68 //7.2 读取消息 69 msg, err = tf.ReadPkg() 70 if err != nil { 71 fmt.Println("ReadPkg(conn) 错误", err) 72 os.Exit(0) 73 } 74 75 //7.3 反序列化 76 77 //将m反序列化为 RegisterResMsg 78 var registerResMsg message.RegisterResMsg 79 err = json.Unmarshal([]byte(msg.Data), ®isterResMsg) 80 81 //判断返回值状态码 82 if registerResMsg.Code == 200 { 83 fmt.Println("注册成功,请登录!") 84 85 /*登陆成功后... 86 1 为客户端启动一个协程,该协程能确保客户端与服务器之间的通讯, 87 若服务器有数据推送给客户端,则接受并显示在客户端终端上 88 2 循环显示登陆成功后的菜单 89 */ 90 go KeepConnection(conn) 91 92 ShouMenu() 93 94 } else { 95 fmt.Println("注册失败,错误:") 96 fmt.Println(registerResMsg.Error) 97 } 98 return 99 100 } 101 102 //Login 登录校验 103 func (up *UserProcess) Login(userID int, userPsw string) (err error) { 104 105 //1 连接服务器 106 conn, err := net.Dial("tcp", "127.0.0.1:9000") 107 if err != nil { 108 fmt.Println("连接服务器失败 ", err) 109 return 110 } 111 112 //延迟关闭数据库通道 113 defer conn.Close() 114 115 //2 连接服务端成功,准备发送数据 116 var msg message.Message 117 msg.Type = message.LoginMsgType 118 119 //3 创建 一个LoginMsg 结构体 120 var loginMsg message.LoginMsg 121 loginMsg.UserID = userID 122 loginMsg.UserPsw = userPsw 123 124 //4 将loginMsg 结构体序列化为json 125 data, err := json.Marshal(loginMsg) 126 if err != nil { 127 fmt.Println("序列化失败! ", err) 128 return 129 } 130 131 //5 将data数据 赋值给 msg.Data 132 msg.Data = string(data) 133 134 //6 将msg 序列化 为json 135 data2, err := json.Marshal(msg) 136 if err != nil { 137 fmt.Println("序列化失败! ", err) 138 return 139 } 140 141 //7 此时 data 就是我们客户端 → 服务端 发送的消息封装结构体 142 var msgLen uint32 = uint32(len(data2)) 143 var buf [4]byte 144 //将 信息长度msgLen 转换为 byte[]切片 145 binary.BigEndian.PutUint32(buf[0:4], msgLen) 146 147 //发送信息长度 148 r, err := conn.Write(buf[:4]) 149 if r != 4 || err != nil { 150 fmt.Println("消息长度发送失败! ", err) 151 return 152 } 153 //fmt.Printf("发送长度成功,长度:%v 内容:%v", len(data2), string(data2)) 154 155 // 发送消息数据本身 156 _, err = conn.Write(data2) 157 if err != nil { 158 fmt.Println("消息长度发送失败! ", err) 159 return 160 } 161 162 //休眠10秒 163 // time.Sleep(time.Second * 10) 164 // fmt.Println("休眠10秒...") 165 //这里处理服务器返回的消息 166 //创建一个Transfer实例 167 168 tf := &utils.Transfer{ 169 Conn: conn, 170 } 171 m, err := tf.ReadPkg() 172 if err != nil { 173 fmt.Println("ReadPkg(conn) 错误", err) 174 } 175 176 //将m反序列化为 LoginResMsg 177 var loginresmsg message.LoginResMsg 178 err = json.Unmarshal([]byte(m.Data), &loginresmsg) 179 180 //判断返回值状态码 181 if loginresmsg.Code == 200 { 182 183 /* 初始化 CurrentUser */ 184 cu.Conn = conn 185 cu.UserID = userID 186 cu.UserStatus = message.OnLine 187 188 fmt.Println("登陆成功,代码200") 189 fmt.Println(loginresmsg.Error) 190 /*显示当前在线用户列表,遍历loginresmsg.UserId*/ 191 for _, v := range loginresmsg.UsersID { 192 //不显示自己 193 if v == userID { 194 continue 195 } 196 fmt.Println("↓在线用户为:↓") 197 fmt.Printf("ID:%v", v) 198 199 /*完成对OnLineUser map的初始化*/ 200 user := &message.User{ 201 UserID: v, 202 UserStatus: message.OnLine, 203 } 204 OnLineUsers[v] = user 205 } 206 fmt.Printf(" ") 207 /*登陆成功后... 208 1 为客户端启动一个协程,该协程能确保客户端与服务器之间的通讯, 209 若服务器有数据推送给客户端,则接受并显示在客户端终端上 210 2 循环显示登陆成功后的菜单 211 */ 212 go KeepConnection(conn) 213 214 ShouMenu() 215 216 } else { 217 fmt.Println("登陆失败,错误:") 218 fmt.Println(loginresmsg.Error) 219 } 220 return 221 }
1 package utils 2 3 import ( 4 "ChatRoom/conmon/message" 5 "encoding/binary" 6 "encoding/json" 7 "fmt" 8 "net" 9 ) 10 11 //Transfer 将下列方法关联到结构体中 12 type Transfer struct { 13 //分析有哪些字段 14 Conn net.Conn // 15 Buf [8096]byte //缓冲区 16 } 17 18 //ReadPkg 读取封包数据 19 func (tf *Transfer) ReadPkg() (msg message.Message, err error) { 20 21 //buf := make([]byte, 8096) 22 23 _, err = tf.Conn.Read(tf.Buf[:4]) 24 25 if err != nil { 26 //自定义错误 27 //err = errors.New("读取数据 头部 错误") 28 return 29 } 30 //根据buf[:4] 转换成一个uint32 31 var pkgLen uint32 32 pkgLen = binary.BigEndian.Uint32(tf.Buf[0:4]) 33 34 //根据 pkgLen的长度读取内容 到 buf中 35 n, err := tf.Conn.Read(tf.Buf[:pkgLen]) 36 if n != int(pkgLen) || err != nil { 37 //自定义错误 38 //err = errors.New("读取数据 内容 错误") 39 return 40 } 41 42 //将pkglen 反序列化为 message.Massage 一定+& 43 err = json.Unmarshal(tf.Buf[:pkgLen], &msg) 44 if err != nil { 45 fmt.Println("反序列化失败! ", err) 46 return 47 } 48 return 49 50 } 51 52 //WritePkg 发送数据 53 func (tf *Transfer) WritePkg(data []byte) (err error) { 54 //1 发送信息长度 55 var msgLen uint32 = uint32(len(data)) 56 // var buf [4]byte 57 //将 信息长度msgLen 转换为 byte[]切片 58 binary.BigEndian.PutUint32(tf.Buf[0:4], msgLen) 59 60 //发送信息长度 61 r, err := tf.Conn.Write(tf.Buf[:4]) 62 if r != 4 || err != nil { 63 fmt.Println("消息长度发送失败! ", err) 64 return 65 } 66 //2 发送信息内容 67 r, err = tf.Conn.Write(data) 68 if r != int(msgLen) || err != nil { 69 fmt.Println("消息长度发送失败! ", err) 70 return 71 } 72 return 73 }
共用项common
1 package message 2 3 /* 4 LoginMsgType 登录消息类型 5 6 LoginResMsgType 登录返回消息类型 7 8 RegisterMsgType 注册消息类型 9 10 RegisterResMsgType 注册返回值信息类型 11 12 PushUserStatusMsgType 服务器推送的用户状态信息类型 13 14 SmsMsgType 发送的消息类型 15 */ 16 const ( 17 LoginMsgType = "LoginMsg" 18 19 LoginResMsgType = "LoginResMsg" 20 21 RegisterMsgType = "Register" 22 23 RegisterResMsgType = "RegisterResMsg" 24 25 PushUserStatusMsgType = "PushUserStatusMsg" 26 27 SmsMsgType = "SmsMsg" 28 ) 29 30 /*用户状态常量 31 32 OnLine 在线 33 34 OffLine 离线 35 36 Busy 繁忙 37 */ 38 const ( 39 OnLine = iota 40 OffLine 41 Busy 42 ) 43 44 //Message 消息结构体 45 type Message struct { 46 //Type 消息类型 47 Type string `json:"type"` 48 49 //Data 消息的数据 50 Data string `json:"data"` 51 } 52 53 //LoginMsg 登录消息结构体 54 type LoginMsg struct { 55 //用户ID 56 UserID int `json:"userid"` 57 //用户名 58 UserName string `json:"username"` 59 //用户密码 60 UserPsw string `json:"userpsw"` 61 } 62 63 //LoginResMsg 登录返回信息结构体 64 /* 65 状态值 66 200 登陆成功 67 404 未注册 68 300 账号密码错误 69 505 服务器内部错误 70 ... 71 72 */ 73 type LoginResMsg struct { 74 Code int `json:"code"` 75 //错误信息 76 Error string `json:"error"` 77 //存放在线所有用的id 78 UsersID []int `json:"usersid"` 79 } 80 81 //RegisterMsg 注册 82 type RegisterMsg struct { 83 User User `json:"user"` 84 } 85 86 //RegisterResMsg 注册返回信息 87 //Code 400表示 用户已存在 200 表示注册成功 88 type RegisterResMsg struct { 89 Code int `json:"code"` 90 //错误信息 91 Error string `json:"error"` 92 } 93 94 /*PushUserStatusMsg 推送用户状态信息 95 96 UserID 用户ID 97 98 Status 用户状态信息值 99 */ 100 type PushUserStatusMsg struct { 101 UserID int `json:"userid"` 102 103 Status int `json:"status"` 104 } 105 106 /* 107 SmsMsg 发送的消息结构体 108 109 Content 发送的内容 110 111 User 匿名结构体 继承关系 user.go 下的 User 结构体 112 */ 113 type SmsMsg struct { 114 Content string `json:"content"` 115 User //匿名结构体 继承关系 user.go 下的 User 结构体 116 }
1 package message 2 3 //User 用户结构体 4 type User struct { 5 UserID int `json:"userid"` //用户通讯ID 6 UserName string `json:"username"` //用户名称昵称 7 UserPsw string `json:"userpsw"` //用户密码 8 UserStatus int `json:"userstatus"` //用户状态值 9 }
服务端sever
1 package main 2 3 import ( 4 "ChatRoom/sever/model" 5 "ChatRoom/sever/processor" 6 7 "fmt" 8 "net" 9 "time" 10 ) 11 12 //Process 处理客户端-服务端之间的通信 13 func Process(conn net.Conn) { 14 15 defer conn.Close() 16 //创建主控 17 processor := &processor.Processor{ 18 Conn: conn, 19 } 20 err := processor.Process2() 21 if err != nil { 22 fmt.Println("客户端 与 服务端之间的协程 出错", err) 23 } 24 } 25 26 //InitUserDao 初始化UserDao 27 func InitUserDao() { 28 fmt.Println("初始化UserDao...") 29 model.MyUserDao = model.NewUserDao(model.Pool) 30 } 31 32 func main() { 33 34 //当服务器启动时,初始化连接池 35 model.InitPool("127.0.0.1:6379", 16, 0, 100*time.Second) 36 37 //初始化pool 38 InitUserDao() 39 40 //提示信息 41 fmt.Println("服务端正在使用新结构[MVC布局],使用9000端口监听") 42 /* net.Listen("tcp","服务器监听IP:端口") 43 可以把这里的IP改成自己的公网IP,客户端连接处改成公网IP就可以实现联网聊天了 44 客户端和服务端的端口和设置的IP一致才可以 45 */ 46 l, err := net.Listen("tcp", "127.0.0.1:9000") 47 defer l.Close() 48 if err != nil { 49 fmt.Println("连接服务器出错 ", err) 50 return 51 } 52 53 //监听成功,等待客户端连接... 54 for { 55 fmt.Println("等待客户端连接...") 56 conn, err := l.Accept() 57 if err != nil { 58 fmt.Println("l.Accept 错误 ", err) 59 } 60 61 //连接服务器成功,起协程服务器客户端-服务端的通信 62 go Process(conn) 63 } 64 }
1 package model 2 3 import "errors" 4 5 //自定义错误 6 /* 7 ErrorUserIsNotFound 用户不存在 8 9 ErrorUserExist 用户已存在 10 11 ErrorUserPsw 用户名或密码错误 12 */ 13 var ( 14 ErrorUserIsNotFound = errors.New("用户不存在") 15 ErrorUserExist = errors.New("用户已存在") 16 ErrorUserPsw = errors.New("用户名或密码错误") 17 )
1 package model 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/gomodule/redigo/redis" 8 ) 9 10 //Pool 连接池 11 var Pool *redis.Pool 12 13 //InitPool 初始化连接池 14 func InitPool(ip string, maxIdle int, maxActive int, idleTimeout time.Duration) { 15 fmt.Println("初始化pool...") 16 Pool = &redis.Pool{ 17 MaxIdle: maxIdle, //最大空闲连接数 18 MaxActive: maxActive, //和数据库最大连接数 0 无限制 19 IdleTimeout: idleTimeout, //最大空闲时间 20 Dial: func() (redis.Conn, error) { 21 return redis.Dial("tcp", ip) 22 }, 23 } 24 }
1 package model 2 3 //User 用户结构体 4 type User struct { 5 UserID int `json:"userid"` 6 UserName string `json:"username"` 7 UserPsw string `json:"userpsw"` 8 }
1 package model 2 3 import ( 4 "ChatRoom/conmon/message" 5 "encoding/json" 6 "fmt" 7 8 "github.com/gomodule/redigo/redis" 9 ) 10 11 //MyUserDao 全局变量 12 var MyUserDao *UserDao 13 14 //UserDao 操作结构体 15 type UserDao struct { 16 pool *redis.Pool 17 } 18 19 //NewUserDao UserDao工厂模式(构造函数) 20 func NewUserDao(pool *redis.Pool) (userdao *UserDao) { 21 userdao = &UserDao{ 22 pool: pool, 23 } 24 return 25 } 26 27 //GetUserID 获取用户ID 28 //根据用户提供的ID,返回一个用户实例+err错误信息 29 func (ud *UserDao) GetUserID(conn redis.Conn, id int) (user *User, err error) { 30 //fmt.Println("进入 GetUserID方法") 31 //查询用户信息 32 res, err := redis.String(conn.Do("hget", "user", id)) 33 //fmt.Println("=================", err) 34 if err != nil { 35 fmt.Println("redis.String(conn.Do 进入!=nil") 36 //如果错误=nil 表示在数据库redis中未找到这个用户 37 if err == redis.ErrNil { 38 fmt.Println("进入了edis.ErrNil ") 39 err = ErrorUserIsNotFound 40 return 41 } 42 return 43 } 44 user = &User{} 45 //将res反序列化为 User实例 46 err = json.Unmarshal([]byte(res), user) 47 if err != nil { 48 fmt.Println("将res反序列化为 User实例失败", err) 49 return 50 } 51 52 return 53 } 54 55 //Login 登录验证 56 /* 57 若 帐号密码不对 则返回 空结构体,err = ErrorUserPsw 58 若 ID未找到 则返回 空结构体,err = ErrorUserIsNotFound 59 */ 60 func (ud *UserDao) Login(userID int, userPsw string) (user *User, err error) { 61 /* 获取连接池中的连接 */ 62 conn := ud.pool.Get() 63 defer conn.Close() 64 65 /* 调用获取信息方法 */ 66 user, err = ud.GetUserID(conn, userID) 67 if err != nil { 68 fmt.Println("d.GetUserID err", err) 69 return 70 } 71 72 /* 成功获取用户信息 */ 73 /* 校验密码 */ 74 if user.UserPsw != userPsw { 75 err = ErrorUserPsw 76 return 77 } 78 return 79 } 80 81 //Register 注册 82 func (ud *UserDao) Register(user *message.User) (err error) { 83 fmt.Println("进入注册方法...") 84 /* 获取连接池中的连接 */ 85 conn := ud.pool.Get() 86 defer conn.Close() 87 88 /* 调用获取信息方法 */ 89 _, err = ud.GetUserID(conn, user.UserID) 90 fmt.Println("***************", err) 91 if err == nil { 92 fmt.Println("进入用户已存在...") 93 //说明用户已存在 94 err = ErrorUserExist 95 return 96 } 97 98 /*执行到这里,表示ID在数据库中不存在,可以注册*/ 99 data, err := json.Marshal(user) 100 if err != nil { 101 fmt.Println("进入序列化失败 ...") 102 return 103 } 104 105 /* 将ID做key ,data做value 存入数据库user中 */ 106 _, err = conn.Do("hset", "user", user.UserID, string(data)) 107 if err != nil { 108 fmt.Println("将注册的用户信息存入数据库失败...", err) 109 return 110 } 111 return 112 }
1 package process 2 3 import ( 4 "ChatRoom/conmon/message" 5 "ChatRoom/sever/utils" 6 "encoding/json" 7 "fmt" 8 "net" 9 ) 10 11 //SmsProcess 服务端消息发送结构体 12 type SmsProcess struct { 13 } 14 15 //PushMsg 转发信息 16 func (sp *SmsProcess) PushMsg(msg *message.Message) { 17 18 /*实例化smsMsg*/ 19 var smsMsg message.SmsMsg 20 /*反序列化msg.Data*/ 21 err := json.Unmarshal([]byte(msg.Data), &smsMsg) 22 if err != nil { 23 fmt.Println("反序列化 msg.Data失败!") 24 return 25 } 26 27 /*序列化msg*/ 28 data, err := json.Marshal(msg) 29 if err != nil { 30 fmt.Println("反序列化msg 失败!") 31 return 32 } 33 34 //遍历服务器端的map,将信息转发给在线用户 35 for id, up := range userManager.OnLineUsers { 36 37 //过滤掉自己,不要发送消息给自己 38 if id == smsMsg.UserID { 39 continue 40 } 41 sp.PushMsgToAllOnLineUser(data, up.Conn) 42 } 43 44 } 45 46 //PushMsgToAllOnLineUser 推送转发消息给在线的所有用户 47 func (sp *SmsProcess) PushMsgToAllOnLineUser(data []byte, conn net.Conn) { 48 49 tf := &utils.Transfer{ 50 Conn: conn, 51 } 52 53 err := tf.WritePkg(data) 54 if err != nil { 55 fmt.Println("发送消息失败... ", err) 56 } 57 }
1 package process 2 3 import "fmt" 4 5 var ( 6 userManager *UserManager 7 ) 8 9 //UserManager 在线用户结构体 10 type UserManager struct { 11 OnLineUsers map[int]*UserProcess 12 } 13 14 func init() { 15 userManager = &UserManager{ 16 OnLineUsers: make(map[int]*UserProcess, 1024), 17 } 18 } 19 20 //AddOnLineUserS 添加在线用户 21 func (um *UserManager) AddOnLineUserS(up *UserProcess) { 22 um.OnLineUsers[up.UserID] = up 23 } 24 25 //DelOnLineUsers 删除在线用户 26 func (um *UserManager) DelOnLineUsers(userid int) { 27 delete(um.OnLineUsers, userid) 28 } 29 30 //GetAllOnLineUsers 获取所有在线用户 31 func (um *UserManager) GetAllOnLineUsers() map[int]*UserProcess { 32 return um.OnLineUsers 33 } 34 35 //GetOnLineUserToID 根据用户ID查找现在用户 36 func (um *UserManager) GetOnLineUserToID(userid int) (up *UserProcess, err error) { 37 up, ok := um.OnLineUsers[userid] 38 if ok { 39 return 40 } 41 //自定义格式化错误 42 err = fmt.Errorf("ID:%d 不在线", userid) 43 44 return 45 46 }
1 package process 2 3 import ( 4 "ChatRoom/conmon/message" 5 "ChatRoom/sever/model" 6 "ChatRoom/sever/utils" 7 "encoding/json" 8 "fmt" 9 "net" 10 ) 11 12 //UserProcess 用户处理器 13 type UserProcess struct { 14 Conn net.Conn 15 //UserId 该字段表示是哪一个用户 16 UserID int 17 } 18 19 //NoticeOnLineUsers 通知在线的用户 userid 上线了 20 func (thisUP *UserProcess) NoticeOnLineUsers(userid int) { 21 for id, up := range userManager.OnLineUsers { 22 //过滤掉自己 23 if id == userid { 24 continue 25 } 26 //开始通知其他人 27 up.NoticeMeOnLine(userid) 28 } 29 } 30 31 //NoticeMeOnLine 通知我上线了 32 func (thisUP *UserProcess) NoticeMeOnLine(userid int) { 33 /*实例化父消息*/ 34 var msg message.Message 35 msg.Type = message.PushUserStatusMsgType 36 37 /*实例化子消息*/ 38 var pushUserStatusMsg message.PushUserStatusMsg 39 pushUserStatusMsg.UserID = userid 40 pushUserStatusMsg.Status = message.OnLine 41 42 /*序列化 子消息结构体*/ 43 data, err := json.Marshal(pushUserStatusMsg) 44 if err != nil { 45 fmt.Println("序列化子消息结构体(pushUserStatusMsg)失败!") 46 return 47 } 48 49 /*将子消息序列化后的封装体data 复制给 父消息结构体中的 data*/ 50 msg.Data = string(data) 51 52 /*序列化 父消息结构体*/ 53 data, err = json.Marshal(msg) 54 if err != nil { 55 fmt.Println("父消息结构体(msg)序列化失败!") 56 return 57 } 58 59 /*创建 Tranfer实例*/ 60 tf := utils.Transfer{ 61 Conn: thisUP.Conn, 62 } 63 /*发送 父消息 */ 64 err = tf.WritePkg(data) 65 if err != nil { 66 fmt.Println("NoticeMeOnLine发送通知失败!") 67 return 68 } 69 70 } 71 72 //SeverProcessRegister 只处理用户注册请求 73 func (thisUP *UserProcess) SeverProcessRegister(msg *message.Message) (err error) { 74 75 /*1 先从msg中取出msg.data,并进行反序列化为registerMsg操作*/ 76 var registerMsg message.RegisterMsg 77 err = json.Unmarshal([]byte(msg.Data), ®isterMsg) 78 if err != nil { 79 fmt.Println("反序列化 registerMsg失败...") 80 return 81 } 82 83 //2 声明 resMsg 84 var resMsg message.Message 85 resMsg.Type = message.RegisterResMsgType 86 //3 声明 registerResMsg 87 var registerResMsg message.RegisterResMsg 88 89 //3 反序列化成功,去数据库完成注册 90 err = model.MyUserDao.Register(®isterMsg.User) 91 92 if err != nil { 93 if err == model.ErrorUserExist { 94 registerResMsg.Code = 500 95 registerResMsg.Error = model.ErrorUserExist.Error() 96 } else if err == model.ErrorUserIsNotFound { 97 registerResMsg.Code = 404 98 registerResMsg.Error = model.ErrorUserIsNotFound.Error() 99 } else { 100 fmt.Println("注册发生错误...") 101 } 102 } else { 103 registerResMsg.Code = 200 104 fmt.Println("注册成功!") 105 } 106 107 //4 序列化 registerResMsg 108 data, err := json.Marshal(registerResMsg) 109 if err != nil { 110 fmt.Println("序列化registerResMsg失败.", err) 111 return 112 } 113 114 //5 将data 赋值给 resMsg(message.Message) 115 resMsg.Data = string(data) 116 117 //6 将resMsg进行序列化 118 data, err = json.Marshal(resMsg) 119 if err != nil { 120 fmt.Println("序列化resMsg失败...", err) 121 return 122 } 123 124 //7 发送 数据 125 //因为使用分布式mvc,我们先创建一个Transfer实例,然后读取 126 tf := &utils.Transfer{ 127 Conn: thisUP.Conn, 128 } 129 err = tf.WritePkg(data) 130 131 return 132 } 133 134 //SeverProcessLogin 只处理登录请求 135 func (thisUP *UserProcess) SeverProcessLogin(msg *message.Message) (err error) { 136 137 /*先从msg中取出msg.data,并进行反序列化操作*/ 138 var loginmsg message.LoginMsg 139 err = json.Unmarshal([]byte(msg.Data), &loginmsg) 140 if err != nil { 141 fmt.Println("反序列化&loginmsg失败...") 142 return 143 } 144 145 //1 声明 resMsg 146 var resMsg message.Message 147 resMsg.Type = message.LoginResMsgType 148 //2 声明 loginResMsg 149 var loginResMsg message.LoginResMsg 150 151 //3 反序列化成功登录验证 152 user, err := model.MyUserDao.Login(loginmsg.UserID, loginmsg.UserPsw) 153 if err != nil { 154 155 if err == model.ErrorUserIsNotFound { 156 loginResMsg.Code = 404 157 loginResMsg.Error = err.Error() 158 } else if err == model.ErrorUserPsw { 159 loginResMsg.Code = 300 160 loginResMsg.Error = err.Error() 161 162 } else { 163 loginResMsg.Code = 505 164 loginResMsg.Error = err.Error() 165 } 166 167 } else { 168 loginResMsg.Code = 200 169 fmt.Printf("%v 登陆成功!", user.UserName) 170 171 /*登陆成功后,将登陆成功的用户放到userManager中*/ 172 thisUP.UserID = loginmsg.UserID 173 userManager.AddOnLineUserS(thisUP) 174 175 /*调用通知在线用户,ID上线了的方法,将登陆ID传入*/ 176 thisUP.NoticeOnLineUsers(loginmsg.UserID) 177 178 /*循环将在线用户的ID添加到LoginResMsg.UsersID切片中*/ 179 for id := range userManager.OnLineUsers { 180 loginResMsg.UsersID = append(loginResMsg.UsersID, id) 181 } 182 } 183 184 //3 序列化 loginResMsg 185 data, err := json.Marshal(loginResMsg) 186 if err != nil { 187 fmt.Println("序列化loginResMsg失败.", err) 188 return 189 } 190 191 //4 将data 赋值给 resMsg(message.Message) 192 resMsg.Data = string(data) 193 194 //5 将resMsg进行序列化 195 data, err = json.Marshal(resMsg) 196 if err != nil { 197 fmt.Println("序列化resMsg失败...", err) 198 return 199 } 200 201 //6 发送 数据 202 //因为使用分布式mvc,我们先创建一个Transfer实例,然后读取 203 tf := &utils.Transfer{ 204 Conn: thisUP.Conn, 205 } 206 err = tf.WritePkg(data) 207 208 return 209 }
1 package processor 2 3 import ( 4 "ChatRoom/conmon/message" 5 "ChatRoom/sever/process" 6 "ChatRoom/sever/utils" 7 "fmt" 8 "io" 9 "net" 10 ) 11 12 //Processor 结构体 13 type Processor struct { 14 Conn net.Conn 15 } 16 17 //SeverProcessMsg 根据客户端发送消息的不同,决定调用哪个函数来处理 18 func (pcs *Processor) SeverProcessMsg(msg *message.Message) (err error) { 19 20 //测试一下是否能接收到来自客户端的群发消息 21 fmt.Println("msg:", msg) 22 23 switch msg.Type { 24 case message.LoginMsgType: 25 //处理登录逻辑... 26 //创建一个UserProcess 实例 27 up := &process.UserProcess{ 28 Conn: pcs.Conn, 29 } 30 err = up.SeverProcessLogin(msg) 31 case message.RegisterMsgType: 32 //处理注册逻辑... 33 //创建一个UserProcess 实例 34 up := &process.UserProcess{ 35 Conn: pcs.Conn, 36 } 37 err = up.SeverProcessRegister(msg) 38 case message.SmsMsgType: 39 //创建一个SmsMsg实例 40 41 smsProcess := &process.SmsProcess{} 42 smsProcess.PushMsg(msg) 43 default: 44 fmt.Println("消息类型不存在,无法处理...") 45 } 46 return 47 } 48 49 //Process2 第二层处理 50 func (pcs *Processor) Process2() (err error) { 51 //读取客户端发送的信息 52 53 for { 54 55 tf := utils.Transfer{ 56 Conn: pcs.Conn, 57 } 58 59 fmt.Println("读取来自客户端的数据中...") 60 msg, err := tf.ReadPkg() 61 62 if err != nil { 63 if err == io.EOF { 64 fmt.Println("客户端断开连接,服务器退出...") 65 return err 66 } 67 fmt.Println("ReadPkg()错误", err) 68 return err 69 70 } 71 //fmt.Println("msg", msgs) 72 err = pcs.SeverProcessMsg(&msg) 73 if err != nil { 74 return err 75 } 76 } 77 }
1 package utils 2 3 import ( 4 "ChatRoom/conmon/message" 5 "encoding/binary" 6 "encoding/json" 7 "fmt" 8 "net" 9 ) 10 11 //Transfer 将下列方法关联到结构体中 12 type Transfer struct { 13 //分析有哪些字段 14 Conn net.Conn // 15 Buf [8096]byte //缓冲区 16 } 17 18 //ReadPkg 读取封包数据 19 func (tf *Transfer) ReadPkg() (msg message.Message, err error) { 20 21 //buf := make([]byte, 8096) 22 23 _, err = tf.Conn.Read(tf.Buf[:4]) 24 25 if err != nil { 26 //自定义错误 27 //err = errors.New("读取数据 头部 错误") 28 return 29 } 30 //根据buf[:4] 转换成一个uint32 31 var pkgLen uint32 32 pkgLen = binary.BigEndian.Uint32(tf.Buf[0:4]) 33 34 //根据 pkgLen的长度读取内容 到 buf中 35 n, err := tf.Conn.Read(tf.Buf[:pkgLen]) 36 if n != int(pkgLen) || err != nil { 37 //自定义错误 38 //err = errors.New("读取数据 内容 错误") 39 return 40 } 41 42 //将pkglen 反序列化为 message.Massage 一定+& 43 err = json.Unmarshal(tf.Buf[:pkgLen], &msg) 44 if err != nil { 45 fmt.Println("反序列化失败! ", err) 46 return 47 } 48 return 49 50 } 51 52 //WritePkg 发送数据 53 func (tf *Transfer) WritePkg(data []byte) (err error) { 54 //1 发送信息长度 55 var msgLen uint32 = uint32(len(data)) 56 // var buf [4]byte 57 //将 信息长度msgLen 转换为 byte[]切片 58 binary.BigEndian.PutUint32(tf.Buf[0:4], msgLen) 59 60 //发送信息长度 61 r, err := tf.Conn.Write(tf.Buf[:4]) 62 if r != 4 || err != nil { 63 fmt.Println("消息长度发送失败! ", err) 64 return 65 } 66 //2 发送信息内容 67 r, err = tf.Conn.Write(data) 68 if r != int(msgLen) || err != nil { 69 fmt.Println("消息长度发送失败! ", err) 70 return 71 } 72 return 73 }