开发者学堂课程【Go 语言核心编程 - 面向对象、文件、单元测试、反射、TCP 编程:海量用户系统-客户端结构改进2】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/626/detail/9806
海量用户系统-客户端结构改进2
内容简介:
一、聊天室的服务器端的程序框架
二、分包
一、聊天室的服务器端的程序框架
服务器端和客户端都有主要的负责文件。例如Common/message有服务器和客户端公用的文件,比如说message.go
1.服务器
(1)main.go:监听;等待客户端的连接;做初始化的工作
(2)Processor.go(总的处理器):
根据客户端的请求,调用相应的处理器,完成相应的任务
(3)smsProcess.go:
处理和短消息相关的请求;群聊;点对点聊天
(4)userProcess.go:
处理和用户相关的请求;登录、注册、注销;用户列表管理
(5)utils.go:
一些常用的工具的函数、结构体;提供常用的方法和函数
2.客户端
(1)main.go:
显示第一级菜单;根据用户的输入,去调用对应的处理器
(2)smsProcess.go:
处理和短消息相关逻辑;私聊;群发
(3)userProcess.go:
处理和用户相关的业务;登录 、注册等等...
(4)server.go
显示登录成功界面;保持和服务器通讯(即启动协程);当读取服务器发送的消息后,就会显示在界面
(5)utils.go:
一些常用的工具的函数,结构体;提供常用的方法和函数
二、分包
1.先把各个文件放到对应的文件夹【包】
客户端,不能三个文件都放在一起。
步骤:
(1)建四个包main、process、utils、model(后面会用到)server可以放在main或者process里。
(2)剥离:不要先把别人的文件或者原先文件马上删掉,要一个一个的剥离。不可能一个功能对应一个文件,这是不现实的。原先文件里面会有一个主文件,复制到main包里面去。
(3)新建两个空的文件,第一个userprocess,是处理跟业务相关的,它跟服务器对接。和服务端的文件同名,本身两个都在不同的大的文件夹下面,这是可以区分的。第二个,专门处理短信的smsProcess.go。
(4)之前的课程有utils文件,可以直接复制到utils包。将server/utils.go 拷贝到 client/utils/utils.go
(5)创建了server/utils.go/userProcess.go
//封装userProcess.go。打包P ackage process.
package process
import(
“fmt”
“net”
“go_code/chatroom/common/message”
“go_code/chatroom/client/utils”
“encoding/binary”
“enconding/json”
)
//这有一个关联,用户怎样登录的一个方法。先把这个结构体写出来
Type Userprocess struct{
//暂时不需要字段..因为它的连接都是自己拿到的,所以这个地方其实是暂时不需要任何东西。
}
//给关联一个用户登录的方法
说明:该文件就是在原来的login.go中做了一个改进,即封装到userProcess结构体(有一些修改的部分如下:)
//创建一个transfer实例
tf := &utis.Transfer{
Conn: conn
}
mes, err = tf.Readpkg()
文件什么都可以不写但必须归属为一个包,
所有文件里面写代码:package process这是一个最基本的原理
(6)创建了server/process/server.go
第一个任务要显示登录成功的界面,写个菜单
第二个保持和通讯
package process
import(
“fmt”
“os”
“go_code/chatroom/client/utils”
“net”
)
//显示登录成功后的界面..
func ShowMenu(){
fmt.Println(“-------恭喜xxx登录成功-------”)
fmt.Println(“-------1.显示在线用户列表-------”)
fmt.Println(“-------2.发送消息-------”)
fmt.Println(“-------3.信息列表-------”)
fmt.Println(“-------4.退出系统-------”)
fmt.Println(“请选择(1-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上来以后先实例化,先把它做成一个全局,哪个地方需要直接用。跟客户服务器端连接是一个连接,只要读的话,直接把它做成一个全局的,或者说把它做成放在一个文件里,直接用更方便。
//创建一个transfer实例,不停的读取服务器发送的消息
tf := &utis.Transfer{
Conn: conn
}
for {//菜单循环
fmt.Println(“客户端%s正在等待读取服务器发送的消息”)
mes , err := tf.ReadPkg()
If err != nil {
fmt.Println(“if.ReadPkg err=”,err)
return
}
// 如果读取到消息,又是下一步处理逻辑
fmt.Printf(“mes=%v\n”,mes)
}
}
(4)server/main/main.go代码修改如下:
package process
import(
“fmt”
“os”
“go_code/chatroom/client/utils”
)
//定义两个变量,一个表示用户id,一个表示用户密码
var userId int
var userPwd string
func main(){
//接收用户的选择
var key int
//判断是否还继续显示菜单
for true {
fmt.Println(“-------欢迎登陆多人聊天系统-------”)
fmt.Println(“\t\t\t 1登陆聊天室”)
fmt.Println(“\t\t\t 2注册用户”)
fmt.Println(“\t\t\t 3退出系统”)
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(“%d\n”,&userPwd)
case 2:
fmt.Println(“注册用户”)
case 3:
fmt.Println(“退出系统”)
os.Exit(0)
default :
fmt.Println(“你的输入有误,请重新输入”)
}
}
(5)在userProcess.go中调用ShowMenu
添加代码如下:
//显示我们的登录成功的菜单[循环]..
for {
ShowMenu()
}
(6)运行 输入用户名和密码正确以后显示
读取客户端发送的数据...
-------恭喜xxx登录成功-------
-------1.显示在线用户列表-------
-------2.发送消息-------
-------3.信息列表-------
-------4.退出系统------
请选择(1-4):
(7)在userProcess.go中
//这里我们还需要在客户端启动一个协程
//该协程保持和服务器端的通讯,如果服务器有数据推送给客户端
//则接收并显示在客户端的终端
(8)在server.go代码的基础上添加:
//和服务器保持通讯
func serverProcessMes(conn net.Conn){
//创建一个transfer实例,不停的读取服务器发送的消息
tf := &utis.Transfer{
Conn: conn
}
for {//连接只要是畅通的,能一直读取消息
fmt.Println(“客户端%s正在等待读取服务器发送的消息”)
mes , err := tf.ReadPkg()
If err != nil {//如果出错就退出
fmt.Println(“if.ReadPkg err=”,err)
return
}
// 如果读取到消息,又是下一步处理逻辑
fmt.Printf(“mes=%v\n”,mes)
}
}
(9)调用
在步骤7的基础上添加:
go serverProcessMes(conn)
(10)再次运行
输入用户名和密码正确以后显示:
读取客户端发送的数据...
-------恭喜xxx登录成功-------
-------1.显示在线用户列表-------
-------2.发送消息-------
-------3.信息列表-------
-------4.退出系统------
请选择(1-4):
客户端正在等待读取服务器发送的消息
读取客户端发送的数据...