当前位置: 首页 > article >正文

go聊天项目4-显示用户列表

一、前言

敬告:本文不讲解代码,只是把代码展示出来。
该代码之前的代码见
go聊天系统项目-3 redis注册用户
注意:本文使用 go mod 管理代码。详情见 go 包相关知识

二、显示在线用户列表 1

修改 server process2 模块 userProcess.go 代码

cat day8/chatroom/server/process/userProcess.go

在 UserProcess 结构体中增加一个字段 UserId

type UserProcess struct {
	//
	Conn net.Conn
	//增加一个字段表示该conn是哪个用户的
	UserId int
}

在 ServerProcessLogin 函数中 fmt.Println(user, "登录成功") 代码之上增加如下代码

//这里,因为用户登录成功,我们就把该登录成功的用户放入到UserMgr中
//将登录成功的用户的UserId赋给this
this.UserId = loginMes.UserId
userMgr.AddOnlineUser(this)
func (this *UserProcess) ServerProcessLogin(mes *message.Message) (err error) {
	//核心代码
	//先从mes 中取出 mes.Data,并直接反序列化成 LoginMes
	var loginMes message.LoginMes
	err = json.Unmarshal([]byte(mes.Data), &loginMes)
	if err != nil {
		fmt.Println("json.Unmarshal fail err=", err)
		return
	}

	// 先声明一个 resMes
	var resMes message.Message
	resMes.Type = message.LoginResMesType

	//再声明一个 LoginResMes
	var loginResMes message.LoginResMes
	//我们需要到redis数据库去完成验证
	//1.使用model.MyUserDao 到redis 去验证
	user, err := model.MyUserDao.Login(loginMes.UserId, loginMes.UserPwd)
	if err != nil {
		if err == model.ERROR_USER_NOTEXISTS {
			loginResMes.Code = 500
			loginResMes.Error = err.Error()
		} else if err == model.ERROR_USER_PWD {
			loginResMes.Code = 403
			loginResMes.Error = err.Error()
		} else {
			loginResMes.Code = 505
			loginResMes.Error = "服务器内部错误"
		}
	} else {
		loginResMes.Code = 200
		//这里,因为用户登录成功,我们就把该登录成功的用户放入到UserMgr中
		//将登录成功的用户的UserId赋给this
		this.UserId = loginMes.UserId
		userMgr.AddOnlineUser(this)
		fmt.Println(user, "登录成功")

	}
	//如果用户id=100,密码=123456,认为合法,否则不合法
	// if loginMes.UserId == 100 && loginMes.UserPwd == "123456" {
	// 	//合法
	// 	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,将其封装到函数中
	//因为使用分层模式(mvc),我们先创建一个 Transfer 实例,然后读取
	tf := &utils.Transfer{
		Conn: this.Conn,
	}
	err = tf.WritePkg(data)
	return
}

修改 common message 模块 message.go 代码

cat day8/chatroom/common/message/message.go

在 LoginResMes 结构体增加如下字段

UsersId []int  //增加字段,保存用户id的切片

修改后的代码

type LoginResMes struct {
	Code    int    `json: "code"`
	UsersId []int  //增加字段,保存用户id的切片
	Error   string `json: "error"`
}

继续修改 server process2 模块 userProcess.go 代码

在 ServerProcessLogin 函数中 fmt.Println(user, "登录成功") 代码之上增加如下代码

//将当前在线用户的id放入到loginMes.UserId
//遍历 userMgr.onlineUsers
for id, _ := range userMgr.onlineUsers {
	loginResMes.UserId = append(loginResMes.UsersId, id)
}

修改 client process 模块 userProcess.go 代码

cat day8/chatroom/client/process/userProcess.go
在 Login 函数 if loginResMes.Code == 200 { 代码后增加如下代码

//fmt.Println("登录成功")
//可以显示当前在线用户的列表,遍历 loginResMes.UsersId
fmt.Println("当前在线用户列表如下:")
for _, v := range loginResMes.UsersId {
	//如果我们要求不显示自己在线,下面我们增加一个代码
	if v == userId {
		continue
	}
	fmt.Println("用户id:\t", v)

}
fmt.Println("\n\n")

三、显示在线用户列表 2

修改 common message 模块 user.go 代码

在 User 结构体 UserName 字段下增加字段

UserStatus int    `json:"userStatus"` //用户状态

修改 common message 模块 message.go 代码

增加 NotifyUserStatusMes 结构体

// 为了配合服务器端推送用户状态变化的消息
type NotifyUserStatusMes struct {
	UserId int `json:"userId"` //用户 id
	Status int `json:"status"` //用户的状态
}

并在常量 const 中增加 NotifyUserStatusMesType = “NotifyUserStatusMes” 常量
如下

const (
	LoginMesType            = "LoginMes"
	LoginResMesType         = "LoginResMes"
	RegisterMesType         = "RegisterMes"
	RegisterResMesType      = "RegisterResMes"
	NotifyUserStatusMesType = "NotifyUserStatusMes"  //新增的
)

增加常量

// 这里我们定义几个用户状态的常量
const (
	UserOnline = iota
	UserOffline
	UserBusyStatus
)

修改 server process2 模块 userProcess.go 代码

增加 NotifyOthersOnlineUser 函数
// 这里我们编写通知所有在线的用户的方法
// userId要通知其他在线用户,我上线
func (this *UserProcess) NotifyOthersOnlineUser(userId int) {
	//遍历 onlineUsers,然后一个一个地发送 NotifyUserStatusMes
	for id, up := range userMgr.onlineUsers {
		//过滤掉自己不要发给自己
		if id == userId {
			continue
		}
		//开始通知 [单独地写一个方法]
		up.NotifyMeOnline(userId)
	}
}

增加 NotifyMeOnline 函数

func (this *UserProcess) NotifyMeOnline(userId int) {
	//组装我们的NotifyUserStatusMes
	var mes message.Message
	mes.Type = message.NotifyUserStatusMesType

	var notifyUserStatusMes message.NotifyUserStatusMes
	notifyUserStatusMes.UserId = userId
	notifyUserStatusMes.Status = message.UserOnline

	//将 notifyUserStatusMes 序列化
	data, err := json.Marshal(notifyUserStatusMes)
	if err != nil {
		fmt.Println("json.Marshal err=", err)
		return
	}
	//将序列化后的 notifyUserStatusMes 赋值给 mes.Data
	mes.Data = string(data)

	//对mes再次序列化,准备发送.
	data, err = json.Marshal(notifyUserStatusMes)
	if err != nil {
		fmt.Println("json.Marshal err=", err)
		return
	}
	//发送,创建我们Transfer实例,发送
	tf := &utils.Transfer{
		Conn: this.Conn,
	}

	err = tf.WritePkg(data)
	if err != nil {
		fmt.Println("NotifyMeOnline err=", err)
		return
	}
}

在 ServerProcessLogin 函数内增加代码

} else {
	loginResMes.Code = 200
	//这里,因为用户登录成功,我们就把该登录成功的用户放入到UserMgr中
	//将登录成功的用户的UserId赋给this
	this.UserId = loginMes.UserId
	userMgr.AddOnlineUser(this)
	//通知其它的在线用户,我上线了
	this.NotifyOthersOnlineUser(loginMes.UserId)  // 增加的代码

修改 client process 包 server.go 代码

serverProcessMes 函数如下代码下

for {
	fmt.Println("客户端%s正在等待读取服务器发送的消息")
	mes, err := tf.ReadPkg()
	if err != nil {
		fmt.Println("tf.ReadPkg err=", err)
		return
	}

增加如下代码

//如果读取到消息,又是下一步处理逻辑
		switch mes.Type{
		case message.NotifyUserStatusMesType: //如果是
			//1.取出 NotifyUserStatusMes
			//2.把这个用户的信息,状态保存到客户 mqp 中
			//处理
		default:
			fmt.Println("服务器端返回了未知的消息类型")
			}
		}

client process 模块增加 userMgr.go 文件

package process

import (
	"day8/chatroom/common/message"
	"fmt"
)

// 客户端要维护的map
var onlineUsers map[int]*message.User = make(map[int]*message.User, 10)

修改 client process 模块 userProcess.go 代码

Login 方法在如下代码下

if loginResMes.Code == 200 {
	//fmt.Println("登录成功")
	//可以显示当前在线用户的列表,遍历 loginResMes.UsersId
	fmt.Println("当前在线用户列表如下:")
	for _, v := range loginResMes.UsersId {
		//如果我们要求不显示自己在线,下面我们增加一个代码
		if v == userId {
			continue
		}
		fmt.Println("用户id:\t", v)

增加如下代码

//完成客户端的 onlineUsers 初始化
user := &message.User{
	UserId:     v,
	UserStatus: message.UserOnline,
}
onlineUsers[v] = user

修改 client process 模块 userMgr.go 代码

增加如下代码

// 在客户端显示当前在线的用户
func outputOnlineUsers() {
	//遍历一把 onlineUsers
	for id, _ := range onlineUsers {
		//如果不显示自己.可以过滤
		fmt.Println("用户id:\t", id)
	}
}

// 编写一个方法,处理返回的NotifyUserStatusMes
func updateUserStatus(notifyUserStatusMes *message.NotifyUserStatusMes) {
	//适当优化
	user, ok := onlineUsers[notifyUserStatusMes.UserId]
	if !ok { //原来没有
		user = &message.User{
			UserId:     notifyUserStatusMes.UserId,
			UserStatus: notifyUserStatusMes.Status,
		}
	}
	user.UserStatus = notifyUserStatusMes.Status
	onlineUsers[notifyUserStatusMes.UserId] = user

	outputOnlineUsers()
}

修改 client process 模块 server.go 代码

在代码

switch mes.Type{
case message.NotifyUserStatusMesType: //有人上线了
	//1.取出 NotifyUserStatusMes

下增加代码

var notifyUserStatusMes message.NotifyUserStatusMes
json.Unmarshal([]byte(mes.Data),&notifyUserStatusMes)
//2.把这个用户的信息,状态保存到客户 mqp[int]User 中
updateUserStatus(&notifyUserStatusMes)

四、显示在线用户列表3

修改 client process 模块 server.go 代码
将 case1:下 fmt 代码注销,增加 outputOnlineUsers 函数调用,如下

case 1:
	//fmt.Println("显示在线用户列表")
	outputOnlineUsers()

四、修改后的代码

server process2 模块 userProcess.go

package process2

import (
	"encoding/json"
	"fmt"
	"net"
	"redis/day8/chatroom/common/message"
	"redis/day8/chatroom/server/model"
	"redis/day8/chatroom/server/utils"
)

type UserProcess struct {
	//
	Conn net.Conn
	//增加一个字段表示该conn是哪个用户的
	UserId int
}

// 这里我们编写通知所有在线的用户的方法
// userId要通知其他在线用户,我上线
func (this *UserProcess) NotifyOthersOnlineUser(userId int) {
	//遍历 onlineUsers,然后一个一个地发送 NotifyUserStatusMes
	for id, up := range userMgr.onlineUsers {
		//过滤掉自己不要发给自己
		if id == userId {
			continue
		}
		//开始通知 [单独地写一个方法]
		up.NotifyMeOnline(userId)
	}
}

func (this *UserProcess) NotifyMeOnline(userId int) {
	//组装我们的NotifyUserStatusMes
	var mes message.Message
	mes.Type = message.NotifyUserStatusMesType

	var notifyUserStatusMes message.NotifyUserStatusMes
	notifyUserStatusMes.UserId = userId
	notifyUserStatusMes.Status = message.UserOnline

	//将 notifyUserStatusMes 序列化
	data, err := json.Marshal(notifyUserStatusMes)
	if err != nil {
		fmt.Println("json.Marshal err=", err)
		return
	}
	//将序列化后的 notifyUserStatusMes 赋值给 mes.Data
	mes.Data = string(data)

	//对mes再次序列化,准备发送.
	data, err = json.Marshal(mes)
	if err != nil {
		fmt.Println("json.Marshal err=", err)
		return
	}
	//发送,创建我们Transfer实例,发送
	tf := &utils.Transfer{
		Conn: this.Conn,
	}

	err = tf.WritePkg(data)
	if err != nil {
		fmt.Println("NotifyMeOnline err=", err)
		return
	}
}

func (this *UserProcess) ServerProcessRegister(mes *message.Message) (err error) {
	//1.先从mes中取出 mes.Data,并直接反序列化成registerMes
	var registerMes message.RegisterMes
	err = json.Unmarshal([]byte(mes.Data), &registerMes)
	if err != nil {
		fmt.Println("json.Unmarshal fail err=", err)
		return
	}

	//2.先声明一个 resMes
	var resMes message.Message
	resMes.Type = message.RegisterResMesType

	var registerResMes message.RegisterResMes
	err = model.MyUserDao.Register(&registerMes.User)
	if err != nil {
		if err == model.ERROR_USER_EXISTS {
			registerResMes.Code = 505
			registerResMes.Error = model.ERROR_USER_EXISTS.Error()
		} else {
			registerResMes.Code = 506
			registerResMes.Error = "注册发生未知错误..."
		}
	} else {
		registerResMes.Code = 200
		//fmt.Println(user, "注册成功")
	}

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

	resMes.Data = string(data)

	data, err = json.Marshal(resMes)
	if err != nil {
		fmt.Println("json.Marshal fail", err)
		return
	}
	tf := &utils.Transfer{
		Conn: this.Conn,
	}
	err = tf.WritePkg(data)
	return
}

func (this *UserProcess) ServerProcessLogin(mes *message.Message) (err error) {
	//核心代码
	//先从mes 中取出 mes.Data,并直接反序列化成 LoginMes
	var loginMes message.LoginMes
	err = json.Unmarshal([]byte(mes.Data), &loginMes)
	if err != nil {
		fmt.Println("json.Unmarshal fail err=", err)
		return
	}

	// 先声明一个 resMes
	var resMes message.Message
	resMes.Type = message.LoginResMesType

	//再声明一个 LoginResMes
	var loginResMes message.LoginResMes
	//我们需要到redis数据库去完成验证
	//1.使用model.MyUserDao 到redis 去验证
	user, err := model.MyUserDao.Login(loginMes.UserId, loginMes.UserPwd)
	if err != nil {
		if err == model.ERROR_USER_NOTEXISTS {
			loginResMes.Code = 500
			loginResMes.Error = err.Error()
		} else if err == model.ERROR_USER_PWD {
			loginResMes.Code = 403
			loginResMes.Error = err.Error()
		} else {
			loginResMes.Code = 505
			loginResMes.Error = "服务器内部错误"
		}
	} else {
		loginResMes.Code = 200
		//这里,因为用户登录成功,我们就把该登录成功的用户放入到UserMgr中
		//将登录成功的用户的UserId赋给this
		this.UserId = loginMes.UserId
		userMgr.AddOnlineUser(this)
		//通知其它的在线用户,我上线了
		this.NotifyOthersOnlineUser(loginMes.UserId)
		//将当前在线用户的id放入到loginMes.UserId
		//遍历 userMgr.onlineUsers
		for id, _ := range userMgr.onlineUsers {
			loginResMes.UsersId = append(loginResMes.UsersId, id)
		}

		fmt.Println(user, "登录成功")

	}

	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,将其封装到函数中
	//因为使用分层模式(mvc),我们先创建一个 Transfer 实例,然后读取
	tf := &utils.Transfer{
		Conn: this.Conn,
	}
	err = tf.WritePkg(data)
	return
}

common message 模块 message.go

package message

const (
	LoginMesType            = "LoginMes"
	LoginResMesType         = "LoginResMes"
	RegisterMesType         = "RegisterMes"
	RegisterResMesType      = "RegisterResMes"
	NotifyUserStatusMesType = "NotifyUserStatusMes"
)

// 这里我们定义几个用户状态的常量
const (
	UserOnline = iota
	UserOffline
	UserBusyStatus
)

type Message struct {
	Type string `josn: "type"`
	Data string `json: "Data"`
}
type LoginMes struct {
	UserId   int    `json: "userId"`
	UserPwd  string `json: "userPwd"`
	UserName string `json: "userName"`
}
type LoginResMes struct {
	Code    int    `json: "code"`
	UsersId []int  //增加字段,保存用户id的切片
	Error   string `json: "error"`
}

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

type RegisterResMes struct {
	Code  int    `json:"code"`  //返回状态码,400表示用户已经存在,200 表示成功
	Error string `json:"error"` //返回错误信息
}

// 为了配合服务器端推送用户状态变化的消息
type NotifyUserStatusMes struct {
	UserId int `json:"userId"` //用户 id
	Status int `json:"status"` //用户的状态
}

common message 模块 user.go

package message

//先定义一个用户的结构体

type User struct {
	UserId     int    `json:"userId"`
	UserPwd    string `json:"userPwd"`
	UserName   string `json:"userName"`
	UserStatus int    `json:"userStatus"` //用户状态
}

client process 模块 userProcess.go

package process

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
	"net"
	"os"
	"redis/day8/chatroom/client/utils"
	"redis/day8/chatroom/common/message"
	//"redis/day8/chatroom/server/utils"
)

type UserProcess struct {
}

func (this *UserProcess) Register(userId int,
	userPwd string, userName string) {
	conn, err := net.Dial("tcp", "localhost:8889")
	if err != nil {
		fmt.Println("net.Dial err=", err)
		return
	}
	//延时关闭
	defer conn.Close()
	//通过conn发送消息给服务
	var mes message.Message
	mes.Type = message.RegisterMesType
	//创建一个LoginMes结构体
	var registerMes message.RegisterMes
	registerMes.User.UserId = userId
	registerMes.User.UserPwd = userPwd
	registerMes.User.UserName = userName
	//将registerMes序列化
	data, err := json.Marshal(registerMes)
	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)
	}
	//创建一个transfer实例
	tf := &utils.Transfer{
		Conn: conn,
	}
	//发送data给服务器端
	err = tf.WritePkg(data)
	if err != nil {
		fmt.Println("注册发送信息错误 err=", err)
	}

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

	//将mes的Data部分反序列化成 RegisterResMes
	var registerResMes message.RegisterResMes
	err = json.Unmarshal([]byte(mes.Data), &registerResMes)
	if registerResMes.Code == 200 {
		fmt.Println("注册成功,请重新登录")
		os.Exit(0)
	} else {
		fmt.Println(registerResMes.Error)
		os.Exit(0)
	}
	return
}

func (this *UserProcess) Login(userId int, userPwd string) (err error) {
	//fmt.Printf("userId = %d userPwd = %s\n", userId, userPwd)
	//return nil
	//连接到服务器
	conn, err := net.Dial("tcp", "localhost:8889")
	if err != nil {
		fmt.Println("net.Dial err=", err)
		return
	}
	//延时关闭
	defer conn.Close()
	//准备通过 conn 发送消息给服务器
	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
	}
	//将data赋值给 message 结构体 Data 字段
	mes.Data = string(data)
	//将 mes 进行序列化
	data, err = json.Marshal(mes)
	if err != nil {
		fmt.Println("json.Marshal err=", err)
		return
	}
	//data是 我们要发送的消息,先发送 data 长度
	//由于 conn 接口的 Write 方法参数要求是 bytes 切片
	var pkgLen uint32
	pkgLen = uint32(len(data))
	var buf [4]byte
	binary.BigEndian.PutUint32(buf[0:4], pkgLen)
	//发送长度
	n, err := conn.Write(buf[0:4])
	if n != 4 || err != nil {
		fmt.Println("conn.Write(bytes) fail", err)
		return
	}
	fmt.Printf("客户端,发送消息的长度=%d,消息内容为: %s\n", len(data), string(data))
	_, err = conn.Write(data)
	if err != nil {
		fmt.Printf("conn.Write(data) fail", err)
		return
	}
	//time.sleep(20*time.Second)
	//fmt.Println("休眠了20S")
	//这里还需要处理服务器返回的消息
	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("登录成功")
		//可以显示当前在线用户的列表,遍历 loginResMes.UsersId
		fmt.Println("当前在线用户列表如下:")
		for _, v := range loginResMes.UsersId {
			//如果我们要求不显示自己在线,下面我们增加一个代码
			if v == userId {
				continue
			}
			fmt.Println("用户id:\t", v)
			//完成客户端的 onlineUsers 初始化
			user := &message.User{
				UserId:     v,
				UserStatus: message.UserOnline,
			}
			onlineUsers[v] = user

		}
		fmt.Println("\n\n")

		//这里我们还需要在客户端启动一个协程
		//该协程保持和服务器端的通讯,如果服务器有数据推送给客户端
		//则接收并显示在客户端的终端
		go serverProcessMes(conn)
		//1.显示登录成功后的菜单
		for {
			ShowMenu()
		}
	} else {
		fmt.Println(loginResMes.Error)
	}

	return
}

client process server.go

package process

import (
	"encoding/json"
	"fmt"
	"net"
	"os"
	"redis/day8/chatroom/client/utils"
	"redis/day8/chatroom/common/message"
)

func ShowMenu() {
	fmt.Println("----------恭喜xxx登录成功--------")
	fmt.Println("--------1、显示在线用户列表--------")
	fmt.Println("--------2、发送消息--------")
	fmt.Println("--------3、信息列表--------")
	fmt.Println("--------4、退出系统--------")
	var key int
	fmt.Scanf("%d\n", &key)
	switch key {
	case 1:
		fmt.Println("显示在线用户列表")
	case 2:
		fmt.Println("发送消息")
	case 3:
		fmt.Println("信息列表")
	case 4:
		fmt.Println("你选择退出了系统...")
		os.Exit(0)
	default:
		fmt.Println("你输入的选项不正确..")
	}
}

// 和服务器保持通讯
func serverProcessMes(conn net.Conn) {
	//创建一个transfer实例,不停的读取服务器发送的消息
	tf := &utils.Transfer{
		Conn: conn,
	}
	for {
		fmt.Println("客户端%s正在等待读取服务器发送的消息")
		mes, err := tf.ReadPkg()
		if err != nil {
			fmt.Println("tf.ReadPkg err=", err)
			return
		}
		//如果读取到消息,又是下一步处理逻辑
		switch mes.Type {
		case message.NotifyUserStatusMesType: //有人上线了
			//1.取出 NotifyUserStatusMes
			var notifyUserStatusMes message.NotifyUserStatusMes
			json.Unmarshal([]byte(mes.Data), &notifyUserStatusMes)
			//2.把这个用户的信息,状态保存到客户 mqp[int]User 中
			updateUserStatus(&notifyUserStatusMes)
			//处理
		default:
			fmt.Println("服务器端返回了未知的消息类型")
		}
		//fmt.Printf("mes=%v", mes)
	}

}

client process userMgr.go

package process

import (
	"fmt"
	"redis/day8/chatroom/common/message"
)

// 客户端要维护的map
var onlineUsers map[int]*message.User = make(map[int]*message.User, 10)

// 在客户端显示当前在线的用户
func outputOnlineUsers() {
	//遍历一把 onlineUsers
	for id, _ := range onlineUsers {
		//如果不显示自己.可以过滤
		fmt.Println("用户id:\t", id)
	}
}

// 编写一个方法,处理返回的NotifyUserStatusMes
func updateUserStatus(notifyUserStatusMes *message.NotifyUserStatusMes) {
	//适当优化
	user, ok := onlineUsers[notifyUserStatusMes.UserId]
	if !ok { //原来没有
		user = &message.User{
			UserId: notifyUserStatusMes.UserId,
		}
	}
	user.UserStatus = notifyUserStatusMes.Status
	onlineUsers[notifyUserStatusMes.UserId] = user

	outputOnlineUsers()
}

编译代码

编译服务端代码

go build -o main main.go

编译客户端代码

go build -o client day8/chatroom/client/main/main.go

运行代码

开3个窗口

第1个窗口运行

./main 

输出

服务器[新的结构]8889 端口监听......
等待客户端连接服务器......

第2个窗口运行

./client 

输出

---------------欢迎登录多人聊天系统-------------------
                         1、登录聊天室
                         2、注册用户
                         3、退出系统
                         请选择(1-3):
1
登录聊天室
请输入用户的id
100
请输入用户密码
123456
客户端,发送消息的长度=86,消息内容为: {"Type":"LoginMes","Data":"{\"UserId\":100,\"UserPwd\":\"123456\",\"UserName\":\"\"}"}
当前在线用户列表如下:



----------恭喜xxx登录成功--------
--------1、显示在线用户列表--------
--------2、发送消息--------
--------3、信息列表--------
--------4、退出系统--------
客户端%s正在等待读取服务器发送的消息

第3个窗口运行

保持前两个窗口运行的程序不退出。

./client 

输出

---------------欢迎登录多人聊天系统-------------------
                         1、登录聊天室
                         2、注册用户
                         3、退出系统
                         请选择(1-3):
1
登录聊天室
请输入用户的id
200
请输入用户密码
123456
客户端,发送消息的长度=86,消息内容为: {"Type":"LoginMes","Data":"{\"UserId\":200,\"UserPwd\":\"123456\",\"UserName\":\"\"}"}
当前在线用户列表如下:
用户id:  100



----------恭喜xxx登录成功--------
--------1、显示在线用户列表--------
--------2、发送消息--------
--------3、信息列表--------
--------4、退出系统--------
客户端%s正在等待读取服务器发送的消息

继续看第2个窗口运行的程序获得了第3个窗口输入的用户id

用户id:  200
客户端%s正在等待读取服务器发送的消息

在第2个窗口输入1显示在线用户列表

1
用户id:  200
----------恭喜xxx登录成功--------
--------1、显示在线用户列表--------
--------2、发送消息--------
--------3、信息列表--------
--------4、退出系统--------

在第3个窗口输入1显示在线用户列表

1
用户id:  100
----------恭喜xxx登录成功--------
--------1、显示在线用户列表--------
--------2、发送消息--------
--------3、信息列表--------
--------4、退出系统--------

http://www.kler.cn/a/412756.html

相关文章:

  • linux模拟HID USB设备及wireshark USB抓包配置
  • 亮相全国集群智能与协同控制大会,卓翼飞思无人智能科研方案成焦点
  • 【leetcode100】轮转数组
  • day11_JS初识_语法
  • 八股文-基础知识-面试题汇总(一)
  • CGAL CGAL::Polygon_mesh_processing::self_intersections解析
  • 比特币安全机制与交易验证体系:私钥、公钥与防伪防篡改的深度解析
  • 如何安全高效地打开和管理动态链接库(DLL)?系统提示dll丢失问题的多种有效修复指南
  • vue 使用el-button 如何实现多个button 单选
  • maven 工具 clean、compile、package、install、deploy 常用命令使用区别
  • 非常简单实用的前后端分离项目-仓库管理系统(Springboot+Vue)part 2
  • 大数据新视界 -- Hive 查询性能优化:索引技术的巧妙运用(下)(6/ 30)
  • [kafka] 基础知识
  • 第21周:机器学习
  • 动静分离具体是怎么实现的?
  • 李宏毅机器学习课程知识点摘要(14-18集)
  • ffplay音视频同步处理
  • 突破Zustand的局限性:与React ContentAPI搭配使用
  • 人工智能零基础入门学习笔记
  • 小程序租赁系统开发的优势与应用解析
  • ES6 、ESNext 规范、编译工具babel
  • 如何将本地项目上传到gitee上
  • 试题转excel;试题整理;试卷转Excel,word试题转excel
  • UE5_建立自己的资产库
  • vue本地调试设置虚拟域名
  • 安全设备-日志审计-报表配置