自学内容网 自学内容网

GO网络编程(六):海量用户通信系统4:读写数据包与登录消息处理

如果你掌握了前三节,接下来就会轻松很多,看老韩的视频也不容易蒙圈了。本节内容不难,分别是读写数据包和登录消息处理。注意,因为上一节(GO网络编程五)把系统框架,目录结构和业务流程都讲了,所以从本节开始,内容会比之前简略。

一、读写数据包

读数据包
总体流程:
1.准备缓冲区
2.读取消息头部并存入缓冲区
3.将缓冲区的消息头部转换成消息长度
4.根据消息长度读取消息内容
5.将消息内容反序列化并返回
代码

// 可以自定义错误变量err,即定义一个新的err,写入自定义的错误内容,
// 但考虑到上层可能要判断err的原本的类型,所以这里直接返回err
// 读数据包
func ReadPkg(conn net.Conn) (mes message.Message, err error) {
fmt.Println("读数据包...")
buf := make([]byte, 1024*4) //1.准备缓冲区
//后续可能会读取更多字节,所以缓冲区大小一般都设置得比较大
//2.读取消息头部并存入缓冲区
n, err := conn.Read(buf[:4])
//conn.Read 在conn没有被关闭的情况下,才会阻塞
//如果客户端关闭了conn,则不会阻塞
if n != 4 || err != nil {
//因为服务端要通过判断err的类型来提示客户端关闭,所以这里什么都不做
return
}
//3.将缓冲区的消息头部转换成消息长度
var pkgLen = binary.BigEndian.Uint32(buf[:4])
//4.根据消息长度读取消息内容
n, err = conn.Read(buf[:pkgLen])
if n != int(pkgLen) || err != nil {
fmt.Println("conn.Read error")
return
}
//5.将消息内容反序列化并返回
err = json.Unmarshal(buf[:pkgLen], &mes)
//由于 mes 是在函数签名中命名的返回值变量,Go 自动为它创建了一个
//初始的 message.Message 类型实例,这样就无需显式声明
if err != nil {
fmt.Println("read pkg body error,json.Unmarshal error")
return
}
return
}

总体流程:
1.准备缓冲区
2.根据消息内容获取消息长度
3.将消息长度存入缓冲区
4.发送消息长度
5.发送消息内容
代码

// 写数据包
func WritePkg(conn net.Conn, data []byte) (err error) {
fmt.Println("写数据包...")
buf := make([]byte, 4) //1.准备缓冲区
//2.根据消息内容获取消息长度
var pkgLen = uint32(len(data))
//3.将消息长度存入缓冲区
binary.BigEndian.PutUint32(buf, pkgLen)
//4.发送消息长度
n, err := conn.Write(buf)
if n != 4 || err != nil {
fmt.Println("conn.Write error")
return
}
//5.发送消息内容
n, err = conn.Write(data)
if n != int(pkgLen) || err != nil {
fmt.Println("conn.Write error")
return
}
return
}

二、登录消息处理

总体流程:
1.先从反序列消息,存在登录消息结构体
2.初始化消息结构体和创建登录响应结构体。
3.判定登录消息结构体的信息并初始化登录响应结构体。
4.序列化登录响应结构体并初始化消息结构体
5.发送消息
代码

// 处理登录消息
func serverProcessLogin(conn net.Conn, mes *message.Message) (err error) {
//1.先从mes中取出mes.Data,并直接反序列化成LoginMes
var loginMes message.LoginMes
err = json.Unmarshal([]byte(mes.Data), &loginMes)
if err != nil {
fmt.Println("json.Unmarshal error:")
return
}
//1初始化一个Mes 结构体
var resMes message.Message
resMes.Type = message.LoginResMesType
//2创建一个LoginResMes 结构体
var loginResMes message.LoginResMes
//如果用户id=100,密码=123456,认为合法,否则不合法
if loginMes.UserID == 100 && loginMes.UserPwd == "123456" {
//合法
loginResMes.Code = 200
} else {
//不合法
loginResMes.Code = 500 //状态码,表示该用户不存在
loginResMes.Error = "该用户不存在,请注册再使用"
}
//3 将loginResMes序列化
data, err := json.Marshal(loginResMes)
if err != nil {
fmt.Println("json.Marshal error:")
return
}
//4.将序列化后的loginResMes作为给resMes的data
resMes.Data = string(data)
//5.对resMes进行序列化,准备发送
data, err = json.Marshal(resMes)
if err != nil {
fmt.Println("json.Marshal error:")
return
}
//6.发送消息
err = utils.WritePkg(conn, data)
if err != nil {
fmt.Println("WritePkg(conn) error:")
return
}
return
}

原文地址:https://blog.csdn.net/weixin_54259326/article/details/142732739

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!