Golang海量用户通讯系统(终端)-下

redis添加用户

  1. 手动添加

package main


import (
    "fmt"
    "net"
    "project_01/server/model"
    "time"
)


func process2(conn net.Conn) {
    // // 延时关闭
    defer conn.Close()


    processor := &Processor{
        Conn: conn,
    }
    err := processor.process3()
    if err != nil {
        fmt.Println("客户端和服务器的通讯协程错误=err", err)
        return
    }
}


// 编写函数,完成对userDao的初始化任务
func initUserDao() {
    model.MyUserDao = model.NewUserDao(pool)
}


func main() {
    // 当服务器启动时,初始化redis的连接池
    initPool("localhost:6379", 8, 0, 300*time.Second)
    initUserDao()
    // 提示信息
    fmt.Println("服务器[新的结构]在8889端口监听...")
    listen, err := net.Listen("tcp", "0.0.0.0:8889")
    // defer listen.Close()
    if err != nil {
        fmt.Println("net.Listen errs=", err)
        return
    }
    for {
        fmt.Println("等待客户端连接服务器")
        conn, err := listen.Accept()
        if err != nil {
            fmt.Println("Listen.Accept err=", err)
            return
        }
        // 一旦链接成功,则启动一个协程和客户端保持通讯
        go process2(conn)
    }
}
package main


import (
    "time"


    "github.com/garyburd/redigo/redis"
)


var pool *redis.Pool


func initPool(address string, maxIdle, maxActive int, idleTimeout time.Duration) {
    pool = &redis.Pool{
        MaxIdle:     maxIdle,
        MaxActive:   maxActive,
        IdleTimeout: idleTimeout,
        Dial: func() (redis.Conn, error) {
            return redis.Dial("tcp", address)
        },
    }
}
package model


import "errors"


var (
    ERROR_USER_NOTEXISTS = errors.New("用户不存在")
    ERROR_USER_EXISTS    = errors.New("用户已经存在")
    ERROR_USER_PWD       = errors.New("密码错误")
)
package model


type User struct {
    UserId   int    `json:"userId"`
    UserPwd  string `json:"userPwd"`
    UserName string `json:"UserName"`
}
package model


import (
    "encoding/json"
    "fmt"


    "github.com/garyburd/redigo/redis"
)


// 在服务器启动后,初始化一个userDao实例
var (
    MyUserDao *UserDao
)


type UserDao struct {
    pool *redis.Pool
}


// 使用工厂模式,创建一个UserDao的实例
func NewUserDao(pool *redis.Pool) (userDao *UserDao) {
    userDao = &UserDao{
        pool: pool,
    }
    return
}


func (pc *UserDao) getUserById(conn redis.Conn, id int) (user *User, err error) {


    // 通过给定id去redis查询这个用户
    res, err := redis.String(conn.Do("HGet", "user", id))
    if err != nil {
        if err == redis.ErrNil {
            err = ERROR_USER_NOTEXISTS
        }
        return
    }
    user = &User{}
    err = json.Unmarshal([]byte(res), user)
    if err != nil {
        fmt.Println("json.Unmarshal err=", err)
    }
    return
}


// Login 完成对用户的验证
// 如果用户的id和pwd都正确,则要返回一个user实例
// 如果用户的id过pwd有错误,则返回对应的错误信息


func (pc *UserDao) Login(userId int, userPwd string) (user *User, err error) {
    conn := pc.pool.Get()
    defer conn.Close()
    user, err = pc.getUserById(conn, userId)
    if err != nil {
        return
    }
    if user.UserPwd != userPwd {
        err = ERROR_USER_PWD
        return
    }
    return
}
package process


import (
    "encoding/json"
    "fmt"
    "net"
    "project_01/common/message"
    "project_01/server/model"
    "project_01/server/utils"
)


type UserProcess struct {
    Conn net.Conn
}


// 编写一个函数serverProcessLogin函数,专登处理登录请求
func (pc *UserProcess) ServerProcessLogin(mes *message.Message) (err error) {
    // 核心代码。。。
    // 先从mes 中去除mes.Data,并直接反序列化成LoginMes
    var loginMes message.LoginMes
    json.Unmarshal([]byte(mes.Data), &loginMes)
    if err != nil {
        fmt.Println("json.Unmarshal fail err=", err)
        return
    }
    fmt.Println(mes)
    //先声明一个resMes
    var resMes message.Message
    resMes.Type = message.LoginResMesType
    // 在声明一个LoginResMes
    var loginResMes message.LoginResMes


    // 使用model.MyUserDao 到redis去验证
    user, err := model.MyUserDao.Login(loginMes.UserId, loginMes.UserPwd)


    if err != nil {
        loginResMes.Code = 500
        loginResMes.Error = "该用户不存在,请注册在使用"
    } else {
        loginResMes.Code = 200
        fmt.Println(user)
    }
    // // 如果用户id = 123,密码= 123123,认为合法,否则不合法
    // if loginMes.UserId == 123 && loginMes.UserPwd == "123123" {
    //  loginResMes.Code = 200


    // } else {
    //  loginResMes.Code = 500
    //  loginResMes.Error = "该用户不存在,请注册在使用"
    // }


    // 将loginResMes 序列化
    data, err := json.Marshal(loginResMes)
    if err != nil {
        fmt.Println("json.Marshal fail", err)
        return
    }


    // 将 data 赋值给 resMes
    resMes.Data = string(data)
    // 对 resMes 进行序列化,准备发送
    data, err = json.Marshal(resMes)


    if err != nil {
        fmt.Println("json.Marshal fail", err)
        return
    }
    // 发送data ,我们将其封装到writePkg函数中


    // 因为使用了分层模式(mvc),我们先创建一个Transfer实例,然后读取
    tf := &utils.Transfer{
        Conn: pc.Conn,
    }
    err = tf.WritePkg(data)
    return
}
package utils


import (
    "encoding/binary"
    "encoding/json"
    "fmt"
    "net"
    "project_01/common/message"
)


// 将方法关联到结构体中
type Transfer struct {
    // 分析有哪些字段
    Conn net.Conn
    Buf  [8096]byte // 传输时,使用缓存
}


func (pc *Transfer) ReadPkg() (mes message.Message, err error) {
    // buf := make([]byte, 8096)
    fmt.Println("读取客户端发送的数据...")
    // conn.Read 在conn没有关闭的情况下,才会发生阻塞
    // 如果客户端关闭了 conn 则,就不会阻塞
    _, err = pc.Conn.Read(pc.Buf[:4])
    if err != nil {
        // fmt.Println("conn.Read err=", err)
        // err = errors.New("read pkg header error")
        return
    }
    // fmt.Println("独到的buf=", buf)
    pkgLen := binary.BigEndian.Uint32(pc.Buf[0:4])


    //根据 pkgKLen 读取消息内容
    n, err := pc.Conn.Read(pc.Buf[:pkgLen])
    if n != int(pkgLen) || err != nil {
        fmt.Println("conn.Read fail err=", err)
        return
    }


    // 把pkgLen 反序列化成 -> message.Message
    err = json.Unmarshal(pc.Buf[:pkgLen], &mes)
    if err != nil {
        fmt.Println("json.Unmarsha err=", err)
    }


    return
}


func (pc *Transfer) WritePkg(data []byte) (err error) {


    // 先发送一个长度给客户端
    pkgLen := uint32(len(data))
    // var buf [4]byte
    binary.BigEndian.PutUint32(pc.Buf[0:4], pkgLen)
    n, err := pc.Conn.Write(pc.Buf[:4])
    if n != 4 || err != nil {
        fmt.Println("conn.Write(bytes) fail", err)
        return
    }


    // 发送 data 本身
    n, err = pc.Conn.Write(data)
    if n != 4 || err != nil {
        fmt.Println("===================")
        fmt.Println("conn.Write(bytes) fail", err)
        return
    }
    return
}

完成注册功能

package main


import (
    "fmt"
    "project_01/client/process"
)


var userId int
var userPwd string
var userName string


func main() {
    // 接收用户的选择
    var key int
    // 判断是否还继续显示菜单
    var loop = true
    for loop {


        fmt.Println("------------------欢迎登录多人聊天系统------------------")
        fmt.Println("\t\t\t1.登陆聊天系统")
        fmt.Println("\t\t\t2.注册用户")
        fmt.Println("\t\t\t3.退出系统")
        fmt.Println("------------------------------------------------------")
        fmt.Println("\t\t\t请选择(1-3):")


        fmt.Scanf("%d\n", &key)
        switch key {
        case 1:
            fmt.Println("登陆聊天系统")
            fmt.Println("请输入你的id号")
            fmt.Scanf("%d\n", &userId)
            fmt.Println("请输入你的密码")
            fmt.Scanf("%s\n", &userPwd)
            // loop = false
            // 创建一个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("请输入用户昵称:")
            fmt.Scanf("%s\n", &userName)
            //调用UserProcess,完成注册的请求
            up := &process.UserProcess{}
            up.Register(userId, userPwd, userName)
            // loop = false
        case 3:
            fmt.Println("退出系统")
            // loop = false
        default:
            fmt.Println("输入有误!请重新选择")
        }
    }


}
package process


import (
    "encoding/binary"
    "encoding/json"
    "fmt"
    "net"
    "os"
    "project_01/client/utils"
    "project_01/common/message"
)


type UserProcess struct {
    //字段..


}


func (pc *UserProcess) Register(userId int, userPwd string, userName 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
    var registerMes message.RegisterMes
    registerMes.User.UserId = userId
    registerMes.User.UserPwd = userPwd
    registerMes.User.UserName = userName


    // 将 registerMes 序列化
    data, err := json.Marshal(registerMes.User)
    if err != nil {
        fmt.Println("json.Marshal err", err)
        return
    }


    // 把data赋给mes.Data字段
    mes.Data = string(data)


    // 将mes进行序列话
    data, err = json.Marshal(mes)
    if err != nil {
        fmt.Println("json.Marshal err", err)
        return
    }


    tf := &utils.Transfer{
        Conn: conn,
    }
    // 发送data给服务器
    err = tf.WritePkg(data)
    if err != nil {
        fmt.Println("注册发送信息错误 err=", err)
    }


    mes, err = tf.ReadPkg() // mes 就是
    if err != nil {
        fmt.Println("readPkg(conn) err=", err)
        return
    }


    // 将mes的Data部分反序列化成 registerMes
    var registerReMes message.RegisterReMes
    err = json.Unmarshal([]byte(mes.Data), &registerReMes)
    if registerReMes.Code == 200 {
        fmt.Println("注册成功!你重新登录一把")
        os.Exit(0)
    } else if registerReMes.Code == 500 {
        fmt.Println(registerReMes.Error)
    }


    return
}


func (pc *UserProcess) Login(userId int, userPwd string) (err error) {
    // 下一步就要开始定协议。。。
    // fmt.Printf("userId=%d\nuserPwd=%s\n", userId, userPwd)
    // return err


    // 1.链接到服务器
    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.LoginMesType
    var loginMes message.LoginMes
    loginMes.UserId = userId
    loginMes.UserPwd = userPwd


    // 将loginMes 序列化
    data, err := json.Marshal(loginMes)
    if err != nil {
        fmt.Println("json.Marshal err", err)
        return
    }
    // 延时关闭
    defer conn.Close()


    // 把data赋给mes.Data字段
    mes.Data = string(data)


    // 将mes进行序列话
    data, err = json.Marshal(mes)
    if err != nil {
        fmt.Println("json.Marshal err", err)
        return
    }
    // data就是我们要发送的信息
    // 先把data的长度发送给服务器
    // 先获取到data长度->转成一个长度的切片
    // conn.Write(len(data))
    pkgLen := uint32(len(data))
    var buf [4]byte
    binary.BigEndian.PutUint32(buf[0:4], pkgLen)
    n, err := conn.Write(buf[:4])
    if n != 4 || err != nil {
        fmt.Println("conn.Write(bytes) fail", err)
        return
    }
    // fmt.Printf("客户端,发送消息的长度=%d\n内容是=%s", len((data)), string(data))


    //  发送消息本身
    _, err = conn.Write(data)
    if err != nil {
        fmt.Println("conn.Write(bytes) fail", err)
        return
    }
    // 还需要处理服务器端返回的消息


    // 创建一个Transfer实例
    tf := &utils.Transfer{
        Conn: conn,
    }
    mes, err = tf.ReadPkg() // mes 就是
    if err != nil {
        fmt.Println("readPkg(conn) err=", err)
        return
    }
    // 将mes的Data部分反序列化成 LoginResMes
    var loginResMes message.LoginResMes
    err = json.Unmarshal([]byte(mes.Data), &loginResMes)
    if loginResMes.Code == 200 {
        // fmt.Println("登陆成功")


        // 需要在客户端启动一个协程
        // 该协程保持和服务器端的通讯,如果服务器有数据推送给客户端
        go ProcessMesServer(conn)


        // 显示我们登录成功的菜单
        for {
            ShowMenu()
        }


    } else if loginResMes.Code == 500 {
        fmt.Println(loginResMes.Error)


    }
    return
}
package utils


import (
    "encoding/binary"
    "encoding/json"
    "fmt"
    "net"
    "project_01/common/message"
)


// 将方法关联到结构体中
type Transfer struct {
    // 分析有哪些字段
    Conn net.Conn
    Buf  [8096]byte // 传输时,使用缓存
}


func (pc *Transfer) ReadPkg() (mes message.Message, err error) {
    // buf := make([]byte, 8096)
    fmt.Println("读取服务器发送的数据...")
    // conn.Read 在conn没有关闭的情况下,才会发生阻塞
    // 如果客户端关闭了 conn 则,就不会阻塞
    _, err = pc.Conn.Read(pc.Buf[:4])
    if err != nil {
        // fmt.Println("conn.Read err=", err)
        // err = errors.New("read pkg header error")
        return
    }
    // fmt.Println("独到的buf=", buf)
    pkgLen := binary.BigEndian.Uint32(pc.Buf[0:4])


    //根据 pkgKLen 读取消息内容
    n, err := pc.Conn.Read(pc.Buf[:pkgLen])
    if n != int(pkgLen) || err != nil {
        fmt.Println("conn.Read fail err=", err)
        return
    }


    // 把pkgLen 反序列化成 -> message.Message
    err = json.Unmarshal(pc.Buf[:pkgLen], &mes)
    if err != nil {
        fmt.Println("json.Unmarsha err=", err)
    }


    return
}


func (pc *Transfer) WritePkg(data []byte) (err error) {


    // 先发送一个长度给客户端
    pkgLen := uint32(len(data))
    // var buf [4]byte
    binary.BigEndian.PutUint32(pc.Buf[0:4], pkgLen)
    n, err := pc.Conn.Write(pc.Buf[:4])


    if n != 4 || err != nil {
        fmt.Println("conn.Write(bytes) fail", err)
        return
    }
    // 发送 data 本身
    n, err = pc.Conn.Write(data)


    if n != int(pkgLen) || err != nil {
        fmt.Println("conn.Write(bytes) fail", err)
        return
    }
    return
}
package message


// 确定消息类型
const (
    LoginMesType      = "LoginMes"
    LoginResMesType   = "LoginResMes"
    RegisterMesType   = "RegisterMes"
    RegisterReMesType = "RegisterReMes"
)


type Message struct {
    Type string `json:"type"` // 消息的类型
    Data string `hson:"data"` // 消息的内容
}


// 定义两个消息


type LoginMes struct {
    UserId   int    `json:"userId"`
    UserPwd  string `json:"userPwd"`
    UserName string `json:"userName"`
}


type LoginResMes struct {
    Code  int    `json:"code"`  // 返回的状态码   500:未注册 200:登陆成功
    Error string `json:"error"` // 返回错误信息
}


type RegisterMes struct {
    User User `json:"code"`
}


type RegisterReMes struct {
    Code  int    `json:"code"`
    Error string `json:"error"`
}
package message


type User struct {
    UserId   int    `json:"userId"`
    UserPwd  string `json:"userPwd"`
    UserName string `json:"userName"`
}
package message


type User struct {
    UserId   int    `json:"userId"`
    UserPwd  string `json:"userPwd"`
    UserName string `json:"userName"`
}
package process


import (
    "encoding/json"
    "fmt"
    "net"
    "project_01/common/message"
    "project_01/server/model"
    "project_01/server/utils"
)


type UserProcess struct {
    Conn net.Conn
}


func (pc *UserProcess) ServerProcessRegister(mes *message.Message) (err error) {
    var registerMes message.RegisterMes
    json.Unmarshal([]byte(mes.Data), &registerMes)
    if err != nil {
        fmt.Println("json.Unmarshal fail err=", err)
        return
    }


    var resMes message.Message
    resMes.Type = message.RegisterReMesType
    var registerReMes message.RegisterReMes


    // 需要到redis数据库去完成注册
    err = model.MyUserDao.Register((*message.User)(&registerMes.User))
    if err != nil {
        if err == model.ERROR_USER_EXISTS {
            registerReMes.Code = 505
            registerReMes.Error = model.ERROR_USER_EXISTS.Error()
        } else {
            registerReMes.Code = 506
            registerReMes.Error = "注册发生未知错误"


        }
    } else {
        registerReMes.Code = 200
    }


    data, err := json.Marshal(registerReMes)
    if err != nil {
        fmt.Println("json.Marshal fail", err)
        return
    }


    // 将 data 赋值给 resMes
    resMes.Data = string(data)
    // 对 resMes 进行序列化,准备发送
    data, err = json.Marshal(resMes)


    if err != nil {
        fmt.Println("json.Marshal fail", err)
        return
    }
    // 发送data ,我们将其封装到writePkg函数中


    // 因为使用了分层模式(mvc),我们先创建一个Transfer实例,然后读取
    tf := &utils.Transfer{
        Conn: pc.Conn,
    }
    err = tf.WritePkg(data)
    return
}


// 编写一个函数serverProcessLogin函数,专登处理登录请求
func (pc *UserProcess) ServerProcessLogin(mes *message.Message) (err error) {
    // 核心代码。。。
    // 先从mes 中去除mes.Data,并直接反序列化成LoginMes
    var loginMes message.LoginMes
    json.Unmarshal([]byte(mes.Data), &loginMes)
    if err != nil {
        fmt.Println("json.Unmarshal fail err=", err)
        return
    }
    fmt.Println(mes)
    //先声明一个resMes
    var resMes message.Message
    resMes.Type = message.LoginResMesType
    // 在声明一个LoginResMes
    var loginResMes message.LoginResMes


    // 使用model.MyUserDao 到redis去验证
    user, err := model.MyUserDao.Login(loginMes.UserId, loginMes.UserPwd)


    if err != nil {
        loginResMes.Code = 500
        loginResMes.Error = "该用户不存在,请注册在使用"
    } else {
        loginResMes.Code = 200
        fmt.Println(user)
    }
    // // 如果用户id = 123,密码= 123123,认为合法,否则不合法
    // if loginMes.UserId == 123 && loginMes.UserPwd == "123123" {
    //  loginResMes.Code = 200


    // } else {
    //  loginResMes.Code = 500
    //  loginResMes.Error = "该用户不存在,请注册在使用"
    // }


    // 将loginResMes 序列化
    data, err := json.Marshal(loginResMes)
    if err != nil {
        fmt.Println("json.Marshal fail", err)
        return
    }


    // 将 data 赋值给 resMes
    resMes.Data = string(data)
    // 对 resMes 进行序列化,准备发送
    data, err = json.Marshal(resMes)


    if err != nil {
        fmt.Println("json.Marshal fail", err)
        return
    }
    // 发送data ,我们将其封装到writePkg函数中


    // 因为使用了分层模式(mvc),我们先创建一个Transfer实例,然后读取
    tf := &utils.Transfer{
        Conn: pc.Conn,
    }
    err = tf.WritePkg(data)
    return
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值