特别提醒:Bug一大堆:先略过....后期在来慢慢修,我先会,然后慢慢优化...希望有大佬指点迷津,谢谢
ReadME.md
#程序框架图:
一、服务器端程序框架图[思路]:
main.go
1.监听
2.等待客户端的连接
3.初始化的任务(一些准备工作)
processor.go
1.管家,根据客户端的求情,请求分发。分配
2.任务调度
3.调用相应的处理器,完成任务
UserProcess.go
1.处理跟用户相关的请求
2.登录、注册、注销、用户信息、列表
SmsProcess.go
1.处理 短消息
2.群聊、点对点
IMProcess.go
FileProcess.go...
二、core核心公用的包
Common.go
User.go
Utils.go
1.工具类 :提供常用的方法和函数
三、客户端程序框架图[思路]:
程序框架
![](https://img.haomeiwen.com/i2021342/a78660c8b1caa4b8.png)
程序框架
效果图:
AppIM/core--package core
Common.go
package core
// 定义消息类型常量
const (
LoginReqMsgType = "LoginReqMsg" // 登录客户端请求消息
LoginResMsgType = "LoginResMsg" // 登录服务端应答消息
RegReqMsgType = "RegReqMsg" // 注册客户端请求消息
RegResMsgType = "RegResMsg" // 注册服务端应答消息
NotifyUserStatusMsgType = "NotifyUserStatusMsg"
SmsMsgType = "SmsMsg"
)
// 用户状态常量
//
const (
Online = iota
Offline
Busy
Gaming
Diamond
)
type Message struct {
Type string `json:"type"` //消息类型
Data string `json:"data"` //消息数据
}
type Repsonse struct {
Code int `json:"code"` //返回状态码
Error string `json:"error"` //返回错误信息
}
// 登录请求消息
type LoginReqMsg struct {
User User `json:"user"`
}
// 登录服务器应答消息
type LoginResMsg struct {
Repsonse
OnlineUsers map[int]*User `json:"onlineUsers"`
}
// 注册请求消息
type RegReqMsg struct {
User User `json:"user"`
}
// 注册服务器应答消息
type RegResMsg struct {
Repsonse
}
// 配合服务器端推送通知用户状态变化的消息
type NotifyUserStatusMsg struct {
User *User `json:"user"`
}
// 消息结构体
type SmsMsg struct {
User
Content string `json:"content"`
}
Error.go
package core
import (
"errors"
)
var (
ERROR_USER_NOTEXISTS = errors.New("用户名不存在,请先注册!")
ERROR_USER_EXISTS = errors.New("用户名已经被注册,请登录!")
ERROR_USER_PWD = errors.New("用户名或密码错误!")
)
Redis.go
package core
import (
"time"
"github.com/garyburd/redigo/redis"
)
var content string = `
————————————————Go语言·redis连接池————————————————————
`
var (
Pool *redis.Pool
)
func InitPool(address string,maxIdle, maxActive int,idleTimeout time.Duration,
password string) {
Pool = &redis.Pool{
MaxIdle: maxIdle, //最大空闲链接数
MaxActive: maxActive, //表示和数据库的最大连接数,0表示没有限制
IdleTimeout: idleTimeout, //最大空闲时间
Dial: func() (redis.Conn, error) {
// 初始化连接
return redis.Dial("tcp", address, redis.DialPassword(password))
},
}
}
User.go
package core
type User struct {
UserID int `json:"userID"` //用户id
UserPwd string `json:"userPwd"` //密码
UserName string `json:"userName"` //用户名
UserStatus int `json:"userStatus"` //用户状态
}
Utils.go
package core
import (
"fmt"
"net"
"errors"
"encoding/binary"
"encoding/json"
)
// 数据传输
type Transfer struct {
// 连接
Conn net.Conn
// 缓冲
buffer [8096]byte
}
/**
* [ReadPkg 读取数据包]
* @author Jhou Shuai
* @datetime 2019-06-15T10:27:55+0800
*/
func (this *Transfer)ReadPkg() (msg Message,err error) {
// fmt.Printf("等待对方发送数据,对方ip=%v \n",this.Conn.RemoteAddr().String())
_,err = this.Conn.Read(this.buffer[:4])
if err != nil {
// err = errors.New("服务器端,读取Pkg长度失败!")
return
}
var pkgLen uint32
pkgLen = binary.BigEndian.Uint32(this.buffer[:4])
// 根据pkgLen读取消息内容
n,err := this.Conn.Read(this.buffer[:pkgLen])
if n != int(pkgLen) || err != nil {
// err = errors.New("服务器端,读取Pkg消息内容失败!")
return
}
//反序列化-》core.Message
err = json.Unmarshal(this.buffer[:pkgLen], &msg)
if err != nil {
err = errors.New("数据包反序列化失败!")
return
}
return
}
/**
* [WritePkg 发送数据包]
* @author Jhou Shuai
* @datetime 2019-06-15T10:27:32+0800
*/
func (this *Transfer)WritePkg(pkgDta []byte) (err error) {
// 先获取到pkgDta的长度
// 发送一个数据包pkgDta长度给对方
// 数据包长度pkgDta---》转成一个表示长度的byte切片
var pkgLen uint32
pkgLen = uint32(len(pkgDta))
binary.BigEndian.PutUint32(this.buffer[0:4],pkgLen)
// 发送包长度
n,err := this.Conn.Write(this.buffer[:4])
if n!=4 ||err != nil {
fmt.Println("数据包长度,发送失败!",err)
return
}
// 发送数据包pkgDta本身
n,err = this.Conn.Write(pkgDta)
if n != int(pkgLen) || err != nil {
fmt.Println("发包失败!",err)
return
}
return
}
AppIM/client/----客户端
AppIM/client/main.go
// 系统程序入口
package main
import (
App "AppIM/client/entry"
)
func main() {
App.InitApp().Go()
}
AppIM/client/entry/Processor.go
package entry
import (
"fmt"
"AppIM/client/process"
)
var menu string = `
-----------欢迎加入多人聊天系统~--------
1.登录
2.注册
3.退出
请选择(1-3)>>> `
type processor struct {
item int //菜单编号
loop bool //表示是否循环显示菜单
ok string //[Y/N]
user *process.UserProcess
}
/**
* 初始胡应用
*/
func InitApp() *processor {
return &processor{
item:0,
loop:false,
ok:"y",
user:process.InitUserProcess(),
}
}
/**
* [Go 启动应用]
* @author Jhou Shuai
* @datetime 2019-06-09T13:44:50+0800
*/
func (this *processor) Go() {
for {
//显示菜单
fmt.Print(menu)
fmt.Scanln(&this.item)
switch this.item {
case 1: //1.登录
this.login()
case 2: //2.注册
this.register()
case 3: //5.退出
this.exit()
default: //其他非法输入
this.otherService()
}
if this.loop {
break
}
}
}
/**
* [otherService 其他服务,暂未开放...]
* @author Jhou Shuai
* @datetime 2019-06-09T13:27:14+0800
*/
func (this *processor) otherService() {
fmt.Println("目前系统不支持此项服务,请重新输入!")
}
/**
* 退出系统
*/
func (this *processor) exit() {
for {
fmt.Print("您确定要退出么?[y/n]")
fmt.Scanln(&this.ok)
if this.ok == "Y" || this.ok == "y" {
fmt.Println()
fmt.Println("[成功退出]多人聊天系统!**********")
this.loop = true
break;
}else if this.ok == "n" || this.ok == "N"{
this.loop = false
break;
}
}
}
/**
* [login 登录]
* @author Jhou Shuai
* @datetime 2019-06-14T16:29:16+0800
*/
func (this *processor) login() {
var (
uid int
pwd string
)
fmt.Print("请输入用户ID>>>")
fmt.Scanln(&uid)
fmt.Print("请输入密码>>>")
fmt.Scanln(&pwd)
this.user.Login(uid, pwd)
}
/**
* [register 注册]
* @author Jhou Shuai
* @datetime 2019-06-14T16:29:16+0800
*/
func (this *processor) register() {
var (
userID int
userPwd string
userName string
)
fmt.Print("请输入注册ID>>>")
fmt.Scanln(&userID)
fmt.Print("请输入用户名>>>")
fmt.Scanln(&userName)
fmt.Print("请输入密码>>>")
fmt.Scanln(&userPwd)
this.user.Register(userID,userPwd,userName)
}
AppIM/client/model/UserModel.go
package model
import (
"net"
"AppIM/core"
)
type CurrUser struct {
*core.User
Conn net.Conn
}
AppIM/client/process
ServerProcess.go
package process
import (
"fmt"
"os"
"net"
"AppIM/core"
"encoding/json"
)
var menu string = `
-----------恭喜<NO.%.4d号[%v]>登录成功,您可以进行如下操作--------
1.在线列表
2.发送消息
3.信息列表
4.查看留言
5.退出系统
请选择(1-5)>>> `
type ServerProcess struct {
item int //菜单编号
loop bool //表示是否循环显示菜单
ok string //[Y/N]
Conn net.Conn
}
/**
* 初始胡应用
*/
func InitApp(conn net.Conn) *ServerProcess {
return &ServerProcess{
item:0,
loop:false,
ok:"y",
Conn:conn,
}
}
/**
* [LoginSucc 登录成功]
* @author Jhou Shuai
* @datetime 2019-06-09T13:44:50+0800
*/
func (this *ServerProcess) LoginSucc(user *core.User) {
for {
//显示菜单
var content string
var smsProcess = &SmsProcess{}
fmt.Printf(menu,user.UserID,user.UserName)
fmt.Scanln(&this.item)
switch this.item {
case 1: //1.在线列表
ShowAllOnlineUser()
case 2: //2.发送消息
fmt.Println("请输入>>>")
fmt.Scanln(&content)
smsProcess.SendGroupMsg(content)
case 3: //3.信息列表
fmt.Println("3.信息列表")
case 4: //4.查看留言
fmt.Println("4.查看留言")
case 5: //5.退出系统
fmt.Println("\n[成功退出]多人聊天系统!**********")
os.Exit(0)
default:
fmt.Println("目前系统不支持此项服务,请重新输入!")
}
if this.loop {
break
}
}
}
// 启动一个协程,保持和服务端的通讯,如果服务器有数据推送
// 给客户端,则可以接收并显示在客户端的终端
func (this *ServerProcess) HandleServerProcess() {
transfer := &core.Transfer{
Conn:this.Conn,
}
for {
msg,err := transfer.ReadPkg()
if err != nil {
fmt.Println("\n服务器连接中断...")
return
}
// 如果读取到消息,进行下一步处理逻辑
fmt.Println("\n新消息来啦!请注意查收...")
switch msg.Type {
case core.NotifyUserStatusMsgType:
// user := &core.User{}
// 取出上线通知
// 把上线用户的信息,保存到客户端的map中
// userMrg.AddOnlineUser()
var notifyUserStatusMsg core.NotifyUserStatusMsg
err = json.Unmarshal([]byte(msg.Data), ¬ifyUserStatusMsg)
if err != nil {
return
}
AddOnlineUser(notifyUserStatusMsg.User)
case core.SmsMsgType:
// 处理消息
showGroupMsg(msg)
default:
fmt.Println("暂时无法处理...",msg)
}
}
}
SmsMrg.go
package process
import (
"fmt"
"AppIM/core"
"encoding/json"
)
func showGroupMsg(msg core.Message) {
var smsMsg core.SmsMsg
err := json.Unmarshal([]byte(msg.Data), &smsMsg)
if err != nil {
fmt.Println("Client反序列化群消息SmsMsg失败!")
return
}
fmt.Println("****************************************")
fmt.Printf("<NO.%.4d号 [%v]>:\n",smsMsg.UserID,smsMsg.UserName)
fmt.Println(smsMsg.Content)
}
SmsProcess.go
package process
import (
"fmt"
"encoding/json"
"AppIM/core"
)
type SmsProcess struct {}
// 发送群聊的消息
func (this *SmsProcess) SendGroupMsg(content string) (err error){
// 1.创建一个msg
var msg core.Message
msg.Type = core.SmsMsgType
var smsMsg core.SmsMsg
smsMsg.Content = content
smsMsg.User = *currUser.User
fmt.Println(smsMsg)
fmt.Println(currUser.Conn)
data,err := json.Marshal(smsMsg)
if err != nil {
fmt.Println("您发送的消息,序列化失败!",err)
return
}
msg.Data = string(data)
msgData,err:= json.Marshal(msg)
if err != nil {
fmt.Println("您发送的消息,序列化失败!",err)
return
}
// msgData,就是我们要发送的消息
transfer := &core.Transfer{
Conn: currUser.Conn,
}
err = transfer.WritePkg(msgData)
if err != nil {
fmt.Println("您发送的消息,发送失败!", err)
return
}
return
}
UserMrg.go
package process
import (
"fmt"
"AppIM/core"
"AppIM/client/model"
)
// 客户端维护的在线列表
var onlineUsers map[int]*core.User = make(map[int]*core.User,10)
// 当前用户信息 全局变量
var currUser model.CurrUser
// 添加在线用户
func AddOnlineUser(user *core.User) {
_,ok := onlineUsers[user.UserID]
if !ok {
onlineUsers[user.UserID] = user
}
onlineUsers[user.UserID].UserStatus = core.Online
ShowAllOnlineUser()
}
// 删除
func DelOnlineUser(userID int) {
delete(onlineUsers, userID)
}
func ShowAllOnlineUser() {
fmt.Println("****************************************")
fmt.Println("当前在线用户列表如下:")
if len(onlineUsers)>0{
for id,userItem := range onlineUsers{
fmt.Printf("<NO.%.4d号 [%v]>~~~在线...\n",id,userItem.UserName)
}
}else{
fmt.Println("暂无...小伙伴儿都在休息...")
}
fmt.Println("****************************************")
}
UserProcess.go
package process
import (
"AppIM/core"
"encoding/json"
"fmt"
"net"
)
type UserProcess struct{}
func InitUserProcess() *UserProcess {
return &UserProcess{}
}
/**
* [login 登录]
* @author Jhou Shuai
* @datetime 2019-06-14T16:29:16+0800
*/
func (this *UserProcess) Login(userID int, userPwd string) (err error) {
// 1.连接到服务器端
conn, err := net.Dial("tcp", "127.0.0.1:8889")
if err != nil {
fmt.Println("网络连接失败咯!", err)
return
}
// 延时关闭
defer conn.Close()
// 2.准备通过conn发送消息给服务器
var msg core.Message
msg.Type = core.LoginReqMsgType
// 3.创建一个LoginReqMsg结构体
var loginReqMsg core.LoginReqMsg
loginReqMsg.User.UserID = userID
loginReqMsg.User.UserPwd = userPwd
// 4.将loginReqMsg序列化
data, err := json.Marshal(loginReqMsg)
if err != nil {
fmt.Println("loginReqMsg数据序列化失败!", err)
return
}
// 5.将loginReqMsg序列化得到的data赋给msg.Data
msg.Data = string(data)
// 6.将msg进行序列化
reqData, err := json.Marshal(msg)
if err != nil {
fmt.Println("ReqMsgData数据序列化失败!", err)
return
}
// 7.reqData,就是我们要发送的消息
transfer := &core.Transfer{
Conn: conn,
}
err = transfer.WritePkg(reqData)
if err != nil {
fmt.Println("消息发送失败!", err)
return
}
msg, err = transfer.ReadPkg()
if err != nil {
fmt.Println("服务器端,没有响应...")
return
}
var loginResMsg core.LoginResMsg
err = json.Unmarshal([]byte(msg.Data), &loginResMsg)
if err != nil {
return
}
if loginResMsg.Code == 200 {
user := &core.User{}
for id,userItem := range loginResMsg.OnlineUsers{
if id == userID {
user = userItem
continue
}
// 初始化在线列表
onlineUsers[id] = userItem
}
fmt.Println("登录成功!")
//当前用户信息
currUser.Conn = conn
currUser.User = user
fmt.Println("当前用户信息:",currUser)
server := InitApp(conn)
// 启动一个协程,保持和服务端的通讯,如果服务器有数据推送
// 给客户端,则可以接收并显示在客户端的终端
go server.HandleServerProcess()
// 1.循环显示菜单:
server.LoginSucc(user)
} else {
fmt.Println(loginResMsg.Error)
}
return
}
/**
* [register 注册]
* @author Jhou Shuai
* @datetime 2019-06-14T16:29:16+0800
*/
func (this *UserProcess) Register(userID int,userPwd,userName string) (err error) {
// 1.连接到服务器端
conn, err := net.Dial("tcp", "127.0.0.1:8889")
if err != nil {
fmt.Println("网络连接失败咯!", err)
return
}
// 延时关闭
defer conn.Close()
// 2.准备通过conn发送消息给服务器
var msg core.Message
msg.Type = core.RegReqMsgType
// 3.创建一个RegReqMsg结构体
var regReqMsg core.RegReqMsg
regReqMsg.User.UserID = userID
regReqMsg.User.UserPwd = userPwd
regReqMsg.User.UserName = userName
// 4.将regReqMsg序列化
data, err := json.Marshal(regReqMsg)
if err != nil {
fmt.Println("regReqMsg数据序列化失败!", err)
return
}
// 5.将regReqMsg序列化得到的data赋给msg.Data
msg.Data = string(data)
// 6.将msg进行序列化
reqData, err := json.Marshal(msg)
if err != nil {
fmt.Println("ReqMsgData数据序列化失败!", err)
return
}
// 7.reqData,就是我们要发送的消息
transfer := &core.Transfer{
Conn: conn,
}
err = transfer.WritePkg(reqData)
if err != nil {
fmt.Println("消息发送失败!", err)
return
}
msg, err = transfer.ReadPkg()
if err != nil {
fmt.Println("服务器端,没有响应...")
return
}
var regResMsg core.RegResMsg
err = json.Unmarshal([]byte(msg.Data), ®ResMsg)
if regResMsg.Code == 200 {
fmt.Println("注册成功,请重新登录!")
} else {
fmt.Println(regResMsg.Error)
}
return
}
IMProcess.go
package process
AppIM/server/----服务器端
AppIM/server/main/main.go
package main
import (
App "AppIM/server/entry"
)
func main() {
// 开始拍片
App.InitIM().Action()
}
AppIM/server/entryProcessor.go
package entry
import (
"AppIM/core"
"AppIM/server/model"
"AppIM/server/process"
"fmt"
"io"
"net"
"time"
)
type processor struct {
Conn net.Conn
}
func InitIM() *processor {
initApp()
return &processor{}
}
// 初始化
func initApp() {
var (
address = "127.0.0.1:6379"
maxIdle = 16
maxActive = 0
idleTimeout = 300 * time.Second
password = "Glen.Jhou@tutengdai.TTD"
)
core.InitPool(address, maxIdle, maxActive, idleTimeout, password)
model.UserHandel = model.NewUserModel(core.Pool)
}
func (this *processor) Action() {
this.listen()
}
// 监听端口,建立连接,启动协程
func (this *processor) listen() {
fmt.Println("服务器在8889端口监听....")
listen, err := net.Listen("tcp", "0.0.0.0:8889")
// 关闭
defer listen.Close()
if err != nil {
fmt.Println("服务器8889端口监听失败:....", err)
return
}
for {
// fmt.Println("8889端口成功,等待客户端连接....")
this.Conn, err = listen.Accept()
if err != nil {
fmt.Println("listen.Accept,Failed....", err)
}
// 一旦连接成功,则启动一个协程,和客户端保持通讯...
go this.actGoroutine()
}
return
}
// 一旦连接成功,则启动一个协程
func (this *processor) actGoroutine() {
// 关闭
defer this.Conn.Close()
err := this.handle()
if err != nil {
fmt.Println("和客户端的通讯协程错误:", err)
return
}
}
// 读取数据包,并分发数据,
func (this *processor) handle() (err error) {
// 关闭
defer this.Conn.Close()
// 循环接收客户端发送的数据
for {
// 读取数据包
transfer := &core.Transfer{
Conn: this.Conn,
}
msg, err := transfer.ReadPkg()
if err != nil {
if err == io.EOF {
fmt.Println("客户端断开连接,服务器也退出...")
return err
} else {
fmt.Println("读取数据包,失败!", err)
return err
}
}
// 打印消息内容
fmt.Println("客户端发送数据:", msg)
// 根据客户端发送消息种类不同,决定调用哪个函数来处理
err = this.serverProcessMsg(&msg)
if err != nil {
return err
}
}
return
}
// 编写一个ServerProcessMsg函数
// 功能:根据客户端发送消息种类不同,决定分配不同任务,调用相应的程序
func (this *processor) serverProcessMsg(msg *core.Message) (err error) {
switch msg.Type {
case core.LoginReqMsgType:
// 处理登录
user := &process.UserProcess{Conn: this.Conn}
err = user.ServerProcessLogin(msg)
case core.RegReqMsgType:
// 处理注册
user := &process.UserProcess{Conn: this.Conn}
err = user.ServerProcessRegister(msg)
case core.SmsMsgType:
// 处理消息
smsProcess := &process.SmsProcess{}
smsProcess.SendGroupMsg(msg)
default:
fmt.Println("消息类型不存在,无法处理!")
}
return
}
AppIM/server/model/UserModel.go
package model
import (
"fmt"
"AppIM/core"
"encoding/json"
"github.com/garyburd/redigo/redis"
)
var (
UserHandel *UserModel
key = "IM:users"
)
type UserModel struct {
pool *redis.Pool
}
// 使用工厂模式,创建一个UserModel的实例
func NewUserModel(pool *redis.Pool) *UserModel {
return &UserModel{
pool:pool,
}
}
// 根据用户id,返回一个User实例 和err
func (this *UserModel) getUserById(redisConn redis.Conn,userID int) (user *core.User,err error) {
// 根据id,去redis查询该用户信息
res ,err := redis.String(redisConn.Do("HGet",key,userID))
if err != nil {
// 表示没有找到用户信息
if err == redis.ErrNil {
err = core.ERROR_USER_NOTEXISTS
}
return
}
user = &core.User{}
err = json.Unmarshal([]byte(res), user)
if err != nil {
fmt.Println("Redis用户数据反序列化失败:",err)
return
}
return
}
// 登录
func (this *UserModel) Login(userID int,userPwd string) (user *core.User,err error){
// 获取redis连接
redisConn := this.pool.Get()
defer redisConn.Close()
// 获取用户信息
user ,err = this.getUserById(redisConn, userID)
if err != nil {
return
}
// 验证用户的密码
if user.UserPwd != userPwd {
err = core.ERROR_USER_PWD
return
}
user.UserStatus = core.Online
user.UserPwd = "(*^__^*) 嘻嘻"
return
}
func (this *UserModel) Register(user *core.User)(err error) {
// 获取redis连接
redisConn := this.pool.Get()
defer redisConn.Close()
_,err = this.getUserById(redisConn, user.UserID)
if err == nil {
// 该用户已经存在咯
err = core.ERROR_USER_EXISTS
return
}
data ,err := json.Marshal(user)
if err != nil {
return
}
_,err = redisConn.Do("HSet",key,user.UserID,string(data))
if err != nil {
return
}
return
}
AppIM/server/process
SmsProcess.go
package process
import (
"fmt"
"net"
"AppIM/core"
"encoding/json"
)
type SmsProcess struct {}
// 转发群消息
func (this *SmsProcess) SendGroupMsg(msg *core.Message) {
// 1.先从msg中取出msg.Data,并直接反序列化成SmsMsg消息
var smsMsg core.SmsMsg
err := json.Unmarshal([]byte(msg.Data), &smsMsg)
if err != nil {
fmt.Println("Server反序列化群消息SmsMsg失败!")
return
}
msgDta,err := json.Marshal(msg)
if err != nil {
fmt.Println("Server反序列化群消息msg失败!")
return
}
// 遍历服务器端 onlineUsers map[int]*UserProcess
for id,userProcess := range userMrg.onlineUsers {
if id == smsMsg.UserID {
continue
}
this.sendMsgToOnlineUser(userProcess.Conn, msgDta)
}
}
func (this *SmsProcess) sendMsgToOnlineUser(conn net.Conn,data []byte) {
// 转发消息
transfer := &core.Transfer{
Conn:conn,
}
err := transfer.WritePkg(data)
if err != nil {
fmt.Println("~~~转发消息失败!")
return
}
}
UserMrg.go
package process
import (
"fmt"
)
var (
userMrg *UserMrg
)
type UserMrg struct {
onlineUsers map[int]*UserProcess
}
// 初始化
func init(){
userMrg = &UserMrg{
onlineUsers : make(map[int]*UserProcess,1024),
}
}
// 添加在线用户
func (this *UserMrg) AddOnlineUser(user *UserProcess) {
this.onlineUsers[user.UserID] = user
}
// 删除
func (this *UserMrg) DelOnlineUser(userID int) {
delete(this.onlineUsers, userID)
}
// 返回所有当前在线的用户
func (this *UserMrg) GetAllOnlineUser() map[int]*UserProcess {
return this.onlineUsers
}
// 根据id返回对应的用户
func (this *UserMrg) GetOnlineUserByID(userID int) (user *UserProcess,err error) {
user,ok := this.onlineUsers[userID]
if !ok {
// 查找的用户当前不在线
err = fmt.Errorf("用户NO.%.4d当前不在线!", userID)
return
}
return
}
UserProcess.go
package process
import (
"fmt"
"net"
"AppIM/core"
"encoding/json"
"AppIM/server/model"
)
type UserProcess struct {
// 连接
Conn net.Conn
// 增加一个字段,表示Conn是那个用户的
UserID int
User *core.User
}
// 上线通知
// 推送通知给其他在线用户,发上线数据包
// userID用户通知其他的用户,我上线咯
func (this *UserProcess) NotifyOthersOnlineUsers() {
for id,userProcess := range userMrg.onlineUsers{
if id == this.User.UserID {
continue
}
// 开始发送通知
userProcess.NotifyOtherUserMeOnline(this.User)
}
}
// 上线通知
func (this *UserProcess) NotifyOtherUserMeOnline(user *core.User)(err error) {
// 上线通知数据包和消息
var msg core.Message
msg.Type = core.NotifyUserStatusMsgType
var notifyUserStatusMsg core.NotifyUserStatusMsg
notifyUserStatusMsg.User = user
data,err := json.Marshal(notifyUserStatusMsg)
if err != nil {
fmt.Println("上线通知数据包序列化失败!",err)
return
}
// 将序列化的数据放到msg包中
msg.Data = string(data)
// 对msg序列化
msgData,err := json.Marshal(msg)
if err != nil {
fmt.Println("上线通知消息包序列化失败!",err)
return
}
// 7.发包
transfer := &core.Transfer{
Conn:this.Conn,
}
err = transfer.WritePkg(msgData)
if err != nil {
fmt.Println("上线通知发送失败!",err)
return
}
return
}
// 处理登录
func (this *UserProcess)ServerProcessLogin(msg *core.Message) (err error) {
// 核心代码
// 1.先从msg中取出msg.Data,并直接反序列化成loginReqMsg消息
var loginMsg core.LoginReqMsg
err = json.Unmarshal([]byte(msg.Data), &loginMsg)
if err != nil {
fmt.Println("反序列化成loginReqMsg消息失败!")
return
}
// 2.先声明一个 发送客户端的消息
var repsMsg core.Message
repsMsg.Type = core.LoginResMsgType
// 服务器应答消息 LoginResMeg
var loginResMsg core.LoginResMsg
// 服务端:redis数据验证
// model.UserHandel.Login
user,err := model.UserHandel.Login(loginMsg.User.UserID, loginMsg.User.UserPwd)
// fmt.Println("Redis数据验证:",user)
if err != nil {
loginResMsg.Code = 500
loginResMsg.Error = err.Error()
}else{
loginResMsg.Code = 200
loginResMsg.Error = "登录成功!"
// 登录成功,把用户放入在线列表
// 将登陆成功的,用户ID,记录
this.UserID = loginMsg.User.UserID
this.User = user
userMrg.AddOnlineUser(this)
// 上线通知
this.NotifyOthersOnlineUsers()
loginResMsg.OnlineUsers = make(map[int]*core.User,10)
for id,userProcess := range userMrg.onlineUsers{
loginResMsg.OnlineUsers[id] = userProcess.User
}
}
// 4.将loginResMsg序列化
data,err := json.Marshal(loginResMsg)
if err != nil {
fmt.Println("loginResMsg数据序列化失败!",err)
return
}
// 5.将loginResMsg序列化得到的data赋给repsMsg.Data
repsMsg.Data = string(data)
// 6.将repsMsg进行序列化
repsData,err := json.Marshal(repsMsg)
if err != nil {
fmt.Println("repsMsg数据序列化失败!",err)
return
}
// 7.发包
transfer := &core.Transfer{
Conn:this.Conn,
}
err = transfer.WritePkg(repsData)
return
}
// 处理登录
func (this *UserProcess)ServerProcessRegister(msg *core.Message) (err error) {
// 核心代码
// 1.先从msg中取出msg.Data,并直接反序列化成RegReqMsg消息
var regMsg core.RegReqMsg
err = json.Unmarshal([]byte(msg.Data), ®Msg)
if err != nil {
fmt.Println("反序列化成注册RegReqMsg消息失败!")
return
}
// 2.先声明一个 发送客户端的消息
var repsMsg core.Message
repsMsg.Type = core.RegResMsgType
// 服务器应答消息 regResMsg
var regResMsg core.RegResMsg
// 服务端注册
// model.UserHandel.Login
err = model.UserHandel.Register(®Msg.User)
fmt.Println("注册信息:",regMsg.User)
if err != nil {
regResMsg.Code = 500
regResMsg.Error = err.Error()
}else{
regResMsg.Code = 200
regResMsg.Error = "注册成功!"
}
// 4.将regResMsg序列化
data,err := json.Marshal(regResMsg)
if err != nil {
fmt.Println("loginResMsg数据序列化失败!",err)
return
}
// 5.将loginResMsg序列化得到的data赋给repsMsg.Data
repsMsg.Data = string(data)
// 6.将repsMsg进行序列化
repsData,err := json.Marshal(repsMsg)
if err != nil {
fmt.Println("repsMsg数据序列化失败!",err)
return
}
// 7.发包
transfer := &core.Transfer{
Conn:this.Conn,
}
err = transfer.WritePkg(repsData)
return
}
IMProcess.go
package process
网友评论