开发者学堂课程【Go 语言核心编程 - 面向对象、文件、单元测试、反射、TCP 编程:海量用户通讯系统-显示在线用户列表(3)】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/626/detail/9815
海量用户通讯系统-显示在线用户列表(3)
内容简介:
一、代码实现功能
二、代码测试及运行结果
一、代码实现功能
1. 功能一
现在已经有了 onlineUsersmap[int] ,且初始化工作已经做完了,因为目前要完成的功能是当用户登录以后就将此东西放进去,所以在事先用户列表肯定有东西才行,那何时往里面添加?就是当一个用户登录成功以后,把此用户的 ID 和 process 放进去就完成了,所以现在需完成这个功能,打开 server/process/userProcess.go ,在其中找到登录成功的位置,是在登录函数里面,即在这里:
} else {
loginResMes.Code = 200
fmt.Println(user,”登录成功”)
}
上文代码表示用户登录成功了,既然登录成功,就应该把用户的 map放进去,即:
} else {
loginResMes.Code = 200
//这里,因为用户登录成功,我们就把该登录的用放入到userMgr中
//将登录成功的用户的userId赋给this
this.UserId = loginMes.UserId
userMgr.AddOnlineUser(this)
fmt.Println(user,”登录成功”)
}
2. 功能一的代码说明
(1)到 server/process/userMgr.go 中时已经初始化了,直接拿来用即可,且它们在同一个包下面,所以直接使用 userMgr 。
(2)注意上文代码中的 this ,在之前已经将 userProcess 做了改进,它里面含有一个新的字段称为 UserId ,所以在添加之前将 UserId放进去,即登录用户的 ID ,
(3)登录用户的 ID 在注册的时候已经把 Mes 反序的化成了 loginMes ,在 Mes 内是含 UserId 的,即用户是哪个用户登录的。
(4)loginMes 的结构是怎样的?打开Common/message/
message.go ,其中包含了一个 userId ,是用户登录时导进去的,所以把它放进去。
3. 功能二
现在想象,当一个用户登录时,就加一个进去,当再有一个用户的时候,就再加进去,所以只要用户登录成功了,就放 ID 和它对应的Conn ,脑海中要有一个动态的想象,既然有了此功能就得使用它,现在想要得到的功能是当用户登录后,可以得到当前在线用户列表的,即有哪些人在线,如何才能让登录的人知道你在线?只有在返回的包里面添加东西,或者在原先的 message 里面加东西,又或者拟一个新的结构体,无论如何都应当有东西,所以目前指针对此功能还是较简单的。可以直接对 message 的结构进行一个小的改进,因为现在代码描述能力很弱,登录成功之后返回一个 loginResMes ,此 ResMes 目前的结构很脆弱,打开 common/message/message.go 会发现它只包含了一个 Code 和一个 Error ,不能发挥作用,这两个信息的客户端也拿不到东西,所以应当至少加一个在线用户 ID 的切片,就好比聊天的软件比如微信,看起来功能很娱乐化,但其实是很难的,它仅次于财务软件,财务软件它的难度是业务逻辑,而像聊天软件它难的是技术,简单的说只是聊天,你发消息他收到,逻辑比较简单,但若要从业务上实现会有一堆东西需处理,所以在common/message/message.go 中增加一个字段,如下:
type LoginResMes struct {
Code int `json:”code”` //返回状态码500表示该用户未注册,200表示登录成功
UsersId []int //增加字段,保存用 ID 的切片
Error string `json:”error”` //返回错误信息
}
完成这一步过后有什么用?当有一个用户登录成功以后,应当返他一个包,现在就有办法返了,现在将返回的 login 、 message 里的user 切片放进去,即找到 server/process/userProcess.go 中登录成功的位置,将其修改为:
} else {
loginResMes.Code = 200
//这里,因为用户登录成功,我们就把该登录的用放入到 userMgr中
//将登录成功的用户的 userId 赋给 this
this.UserId = loginMes.UserId
userMgr.AddOnlineUser(this)
//将当前在线用户的 id 放入到loginResMes.UserId
//遍历 userMgr.onlineUsers
for id, _ := range userMgr.onlineUsers {
loginResMes.UsersId = append(loginResMes.UsersId,id)
}
fmt.Println(user,”登录成功”)
}
其中 for 循环中是需要它的 ID 值,所以说写 id ,它里面的UserMgr.go 暂时用不上,因为现在不是一些通化,如果是群发消息点对点就非常有用,也暂时用不到 Conn net ,暂时用 id ,所以先不去取 usersProcess ,这时就可以试着测试一下返回的loginResMes 有没有东西,在此就不做测试了。
现在要想象在返回的 loginResMes 里面已经有切片了,这里面就是当前在线用户的 ID ,这样还没有完成,还需做一件事,即在UserMgr.go 中拿到东西回给客户端的 userProcess.go ,它登录成功过后,它是否接受 loginResMes ,需要解析并展现出来就可以了。
接下来接着写下一步工作,上文代码已经将 loginResMes 封装起来了,在文件中找到 chartroom/client/process/userProcess.go ,在其内找到登录成功的位置,添加或修改成为以下代码:
//fmt.Println(“登录成功”)
//可以显示当前在线用户列表,遍历loginResMes.UsersId
fmt.Println(“当前在线用户列表如下:”)
for _, v := range loginResMes.UsersId {
fmt.Println(“用户ID:\t”,v)
}
fmt.Println(“\n\n”)
其中 for 关心的是值而不是关心它的索引, userId 索引是按照顺序加进去的,现在关心的是 ID ,所以此时关心的恰恰相反,切片里的值才是存进去的用户 ID 值。
二、代码测试及运行结果
1. 代码运行前准备工作
①将文件整个保存,运行一下检测第一个功能是否完成,因为和服务器有关,所以需先把 Redis启动,再启动客户端(其中虽然客户端不是必须启动的,但是由于有些客户端是原先启动的,有些乱七八糟容易搞混淆,所以干脆把它们清掉再重新启动),将客户端清成以下形式:
l27.D.D.l :6379> f lushdb
OK
l27.D.D.l :6379> f lushdb
OK
l27.D.D.l :6379> hget users 100
l27.D.D.l :6379>
②现在找到计算机 D 盘,进入 goproject 里,然后启动服务器端,显示:
Microsoft Windows [版本 6.1.7601 ]
版权所有 2009 Microsoft Corporation。保留所有权利。
D:\goproject>go build -o server.exe go_code/chatroom/server/main
D:\goproject>server.exe
服务器[新的结构]在8889端口监听....
等待客户端来连接服务器....
③紧接着再启动客户端,客户端至少要启两个才可以,运行第一个结果为:
D:\goproject>go build -o server.exe go_code/chatroom/server/main
D:\goproject>server.exe
------------------欢迎登陆多人聊天系统-------------------
1 登陆聊天室
2 注册用户
3 退出系统
请选择<1-3>:
1
登陆聊天室
请输入用户的id
100
请输入用户的密码
123456
客户端,发送消息的长度=86 内容=(“type”:”LoginMes”,”data”:”<\”userId\”:100,\”userPwd\”:\“123456”)
用户不存在。。
2.注册用户与代码运行
(1)因为上文中是没有注册过的,所以显示用户不存在,现在来注册一个如下:
------------------欢迎登陆多人聊天系统-------------------
1 登陆聊天室
2 注册用户
3 退出系统
请选择<1-3>:
2
注册用户
请输入用户id:
100
请输入用户密码:
123456
请输入用户名字:
tom
读取客户端发送的数据。。。
注册成功,你重新登录一把
D:\goproject>server.exe
------------------欢迎登陆多人聊天系统-------------------
1 登陆聊天室
2 注册用户
3 退出系统
请选择<1-3>:
1
登陆聊天室
请输入用户的id
100
请输入用户的密码
123456
客户端,发送消息的长度=86 内容=(“type”:”LoginMes”,”data”:”<\”userId\”:100,\”userPwd\”:\“123456”)
当前在线用户列表如下:
用户id: 100
----------恭喜xxx登录成功----------
----------1.显示在线用户列表----------
----------2.发送消息-------------
---------3.信息列表-------------
---------4.退出系统-------------
请选择<1-4>:
客户端正在等待读取服务器发送的消息
读取客户端发送的数据。。。
(2)再来登录一个包,现在目前客户端只有一个人在线了,再来注册一个,结果如下所示:
D:\goproject>server.exe
------------------欢迎登陆多人聊天系统-------------------
1 登陆聊天室
2 注册用户
3 退出系统
请选择<1-3>:
2
注册用户
请输入用户id:
200
请输入用户密码:
123456
请输入用户名字:
jack
读取客户端发送的数据。。。
注册成功,你重新登录一把
D:\goproject>server.exe
------------------欢迎登陆多人聊天系统-------------------
1 登陆聊天室
2 注册用户
3 退出系统
请选择<1-3>:
1
登陆聊天室
请输入用户的id
200
请输入用户的密码
123456
客户端,发送消息的长度=86 内容=(“type”:”LoginMes”,”data”:”<\”userId\”:100,\”userPwd\”:\“123456”)
当前在线用户列表如下:
用户id: 100
用户id: 200
----------恭喜xxx登录成功----------
----------1.显示在线用户列表----------
----------2.发送消息-------------
---------3.信息列表-------------
---------4.退出系统-------------
请选择<1-4>:
客户端正在等待读取服务器发送的消息
读取客户端发送的数据。。。
3. 运行结果分析
可以看到显示有两个人在线,但是第一个包中并没有变化,这是不行的,且恐怖的是如果再输入1,是否还可以再获得一个在线用户,显然是不可以的,只要返回一次就跑路了,现在还是有一个很麻烦的事情,就是客户端这边还得有一个东西维护在线用户,所以这里并不简单。