开发者学堂课程【Go 语言核心编程 - 面向对象、文件、单元测试、反射、TCP 编程:海量用户通讯系统-用户注册(2)】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/626/detail/9812
海量用户通讯系统-用户注册(2)
目录:
一、common/message/user.go
二、common/message/message.go
三、clientproces/userProcess.
四、在 dieatmain/main.go 增加了代码
五、在 server modeluserDao.go
六、Processor.go
一、common/message/user.go
package message
//定义一个用户的结构体
type User struct {
//确定字段信息
//为了序列化和反序列化成功,我们必须保证
//用户信息的json字符串的key 和 结构体的字段对应的 tag 名字一致!!! UserId int `json:"userid"
UserPwd string`json:"userPwd" UserName string `json:"userName"}
二、common/message/message.go
package message
const(
LoginmesType "LoginMes"
LoginResMesType "LoginResMes"
RegisterMesType "RegisterMes"
)
type Message struct {
Type string `json:"type"
//消息类型
Data string*json:"data"*
//消息的类型
//定义两个消息..后面需要再增加
type LoginMes struct {
UserId int `json:"userId"
//用户id
UserPwd string `json:"userPwd"*
//用户密码 UserName string `json:"userName""
//用户名
type LoginResMes struct {
Code int*json:"code"*
// 返回状态码500表示该用户未注册 200表示登录成功 Error string `json:"error""
// 返回错误信息
Error String json :error
//返回错误信息
type Reristerhes struct {
User User
//类型就是User结构体。
}
Code int json: "code-"返回状态码400表示该用户已经占有200表示注册成功
Error string、'json:"error"
//返回错误信息
三、clientproces/userProcess.
package process import(
"fmt""net"
"go_code/chatroom/common/message""go code/chatroom/client/utils""encoding/binary"
"encoding/json"
"os"
type UserProcess struct {
//暂时不需要字段..}
func(this *UserProcess)Register(userId int,
userPwd string, userName string)(err error){
//1.链接到服务器
conn, err := net.Dial("tcp","localhost:8889") if err != nil {
fmt.Println("net.Dial err=", err) return
//延时关闭
defer conn.close))
//2,准备通过conn发送消息给服务 var mes message.Message
mes.Type = message.RegisterMesType
//3.创建一个LoginMes 结构体
var registerMes message.RegisterMes registerMes.User.UserId =userId registerMes.User.UserPwd =userPwd registerMes.User.UserName = userName
//4.将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 {
//将mes的Data部分反序列化成 RegisterresMes var registerResMes message.RegisterResMes
err =json.Unmarshal([]byte(mes.Data),®isterResMes) if registerResMes.Code == 200 {
fmt.Println("注册成功,你重新登录一把")
} else {
fmt.Println(registerResMes.Error)
os.Exit(0)
return I
//给关联一个用户登录的方法
//写一个函数,完成登录
func(this *UserProcess) Login(userId int, userPwd string)(err error){
//下一个就要开始定协议.
// fmt.Printf(" userId = %d userPwd=%s\n", userId, userPwd)for true {
fmt.Println("_ ...- ----欢迎登陆多人聊天系统------------"
fmt.Println("\t\t\t 1 登陆聊天室") fmt.Println("\t\t\t 2 注册用户") fmt.Println("\t\tlt3 退出系统") fmt.Println("\t\t\t 请选择(1-3):")
fmt.Scanf("%d\n",&key) switch key
case 1:
fmt.Println("登陆聊天室") fmt.Println("请输入用户的id
fmt.Println("请输入用户的id") fmt.Scanf("%d\n",&userId)
fmt.Println("请输入用户的密码") fmt.scanf("%s\n",&userPwd)
// 完成登录
//1、创建一个UserProcess的实例 up :=&process.UserProcess() up.Login(userId,userPwd) case 2 :
fmt.Println("注册用户")
fmt.Println("请输入用户id:") fmt.Scanf("%d\n",&userId)
fmt.Println("请输入用户密码:" fmt.Scanf("%s\n",&userPwd)
fmt.Println("请输入用户名字(nick):" fmt.scanf("%s\n",&userPwd) case 3 :
fmt.Println("退出系统")
//loop = false os.Exit(e) default :
fmt.Println("你的输入有误,请重新输入")
}
}
//更加用户的输入,
显示新的提示信息
//if key==1{
// / 说明用户要登陆
//fmt.Print1n("请输入用户的id")
7,到这个时候 data就是我们要发送的消息
7.1 先把 data的长度发送给服务器
// 先获取到 data的长度->转成一个表示长度的byte切片
var pkgLen uint32
pkgLen = uint32(len(data)) var buf [4]byte
binary.BigEndian.PutUint32(buf[e:4],pkgLen)
// 发送长度
n,err := conn.Write(buf[:4]) if n != 4 ll err != nil {
fmt.Println("conn.Write(bytes)fail", err) return}
fmt.Printf("客户端,发送消息的长度=%d内容=%s",len(data),string(data))
// 发送消息本身
err = conn.Write(data) if err != nil {
fmt.Println("conn.Write(data)fail",err) return}
//休眠20
time.Sleep(20. timesecond
// fnt.Print1n("休眠了20.")
//这里还需要处理服务器端返回的消息。
//创建一个Transfer 实例 tf:=&utils.Transfer{
Conn:conn,
mes, err =tf.ReadPkg()
//mes 就是
if err l= ni1 {
fmt.Println("readpkg(conn)err-", err) return}工
//将mes的Data部分反序列化成LoginresMes var loginResMes message.LoginResMes
err =json.Unmarshal([]byte(mes.Data),&loginResMes)
1先把user.go放入到common/message文件夹.
2. common/message/message.go 新增加两个消息类型
3.在客户端接收用户的输入
4.在client/process/userProcess.go 增加一个Register方法,完成请求注册
四、在 dieatmain/main.go 增加了代码
godeichatroom Clnentiprocess
//定义两个变量,一个表示用户id,一个表示用户密码 var userid int
var userPwd string var userName string
func main() {
//接收用户的选择 var key int
//判断是否还继续显示菜单
//var loop = trde
五、 在 server modeluserDao.go
package model
import(
"fmt"
"github.com/garyburd/redigo/redis" go code/chatroom/common/message"encoding/json"
//我们在服务器启动后,就初始化一个userDao实例,
//把它做成全局的变量,在需要和redis操作时,就直接使用即可 var
MyUserDao *UserDao
//定义一个UserDao 结构体体//完成对User 结构体的各种操作。
type UserDao struct {
pool*redis.Pool
//使用工厂模式,创建一个UserDao实例
func NewUserDao(pool *redis.Pool)(userDao *UserDao){
userDao = &UserDaof
pool pool
return
考一下在UserDao 应该提供哪些方法给我们根据用户id 返回 一个User实例+err
(this *UserDao)getUserById(conn redis.Conn, id int)(user *User, err error)
//通过给定id 去 redis查询这个用户
res, err := redis.string(conn.Do("HGet", "users", id)) if err != nil {
//错误!
if err == redis.ErrNil {
//表示在users 哈希中,没有找到对应id
err = ERROR USER NOTEXISTS}
return
user = &User0)
//这里我们需要把res 反序列化成User实例 err=json.Unmarshal([]byte(res),user) if err != nil {
fmt.Println("json.Unmarshal err=", err) return
}
//完成登录的校验 Login
//1.Login 完成对用户的验证
//2。如果用户的id和pwd都正确,则返回一个user实例//3.如果用户的id或pwd有错误,则返回对应的错误信息
func(this *UserDao) Login(userId int, userPwd string)(user *User, err error){
//先从userDao 的连接池中取出一根连接 conn := this.pool.Get() defer conn.close()
user, err = this.getUserById(conn, userId) if err != nil {
return
//这时证明这个用户是获取到。 if user.UserPwd != userPwd {
err =ERROR_USER_PWD return
return
func (this *UserDao) Register(user *message.User)(err error){
//先从userDao 的连接池中取出一根连接 conn := this.pool.Geto)
err =this.getUserById(conn, user.UserId) if err == ni1 {
err =ERROR USER EXISTS return}
//这时,说明id在redis还没有,则可以完成注册 data,err := json.Marshal(user)//序列化 if err != nil {
return}
//入库
err =conn.Do("HSet", "users", user.UserId, string(data))
日 if err != nil {
fmt.Println("保存注册用户错误 err=",err) return}
return}
//编写一个ServerProcessMes 函数
//功能:根据客户端发送消息种类不同,决定调用哪个函数来处理
func (this *Processor)serverProcessMes(mes *message.Message)(err error){
switch mes.Type {
case message.LoginMesType:
六、Processor.go
//处理登录登录
//创建一个UserProcess实例
up :=&process2.UserProcess
Conn :this.conn,}
err =up.ServerProcessLogin(mes) case message.RegisterMesType :
//处理注册
up :=&process2.UserProcess{
Conn :this.Conn,}
err =up.ServerProcessRegister(mes) default :
fmt.Println("消息类型不存在,无法处理...")
return
func(this *Processor)process2()(err error){