客户端和服务端运行后,客户端输入用户名和密码后,程序就不动卡住了, ReadPKG()函数加入for循环就会卡住,不加就不卡,为什么呢?
func (t *Transfer) ReadPKG() (mes Message, err error) {
for {
//t.Conn.Read(...) 会起到阻塞作用,有消息时,for循环就不停的循环读取消息,没有消失时,就阻塞在这里
_, err = t.Conn.Read(t.Buff[:4]) //先读取长度(因为 binary.BigEndian.Uint32 方法最大占4个字节的内存,而Buff字段变量分配了1024个字节,所以读取长度时截取4个字节长度的内存)
fmt.Println("无限循环????????????????????")
if err != nil {
if err == io.EOF { //这里只需添加该错误语句,别处不需要,因为这里是开头,for语句再次循环到这里没有文件末尾没有数据时,直接return该错误,下面的 t.Conn.Read 执行不到了
fmt.Println("ReadPKG() ->> err == io.EOF 会走这里吗???????????????????????")
return
}
fmt.Println("ReadPKG() ->> t.Conn.Read(t.Buff[:4]) err", err)
return //这里不带返回参数,默认就是返回 mes 和 err
}
pkgLen := binary.BigEndian.Uint32(t.Buff[:4]) //将这4个字节切片转换成一个无符号整数pkgLen(这里使用了大端序(BigEndian)进行编解码)
var n int
n, err = t.Conn.Read(t.Buff) //后读取真正的消息; 在for 循环内部使用 := 运算符会创建一个新的变量,而不是对已有的变量赋值,所以会报错:"返回时结果参数err不在范围内",因此可将 err 的定义改为赋值操作,而不使用 := 运算符 ,或者定义并返回新的错误变量,如"return otherErr"
if err != nil {
fmt.Println("ReadPKG() ->> t.Conn.Read(t.Buff) err")
return
} else if pkgLen != uint32(n) { //如果先发来的长度和后发来的消息长度不一样,则可能丢包
return mes, errors.New("客户端的数据大小与服务端的数据大小不一致,疑似丢包")
}
//把总消息反序列化为具体消息结构体类型(序列化后的)
err = json.Unmarshal(t.Buff[:n], &mes)
if err != nil {
fmt.Println("ReadPKG() ->> json.Unmarshal(t.Buff[:n], &mes) err")
return
}else{
break
}
}
return mes, nil //返回值可省略; 当 err == io.EOF 的时候,说明读取数据完毕,没有数据了,这个时候就break跳出无限循环,把结果返回
}
// loginRequest:登录请求函数
func (p *Process) LoginRequest(mes common.Message) {
//先从mes中取出 MessData,并反序列化为LoginMes
var loginMes common.LoginMes
err := json.Unmarshal([]byte(mes.MessData), &loginMes)
if err != nil {
fmt.Println("json.Unmarshal([]byte(mes.MessData), &loginMes) err:", err)
return
}
//提前定义总消息,和返回结果消息,总比发送给客户端(为了告知客户端用户id是否在服务器端存在)
var resultMessage common.Message
var returnResMes common.ReturnResMes
//如果用户id=tom,密码123,就认为合法,否则不合法
if loginMes.UserId == "tom" && loginMes.UserPwd == "123" {
returnResMes.Code = 1 //1代表真,说明合法
} else {
returnResMes.Code = 0 //0代表假,说明不合法,表示用户不存在
}
//将returnResMes 序列化
ret_ByteSli, err := json.Marshal(returnResMes)
if err != nil {
fmt.Println("json.Marshal(returnResMes) err:", err)
return
}
//将返回类型和返回结果的两个消息赋给resultMessage(总消息)
resultMessage.MessData = string(ret_ByteSli)
resultMessage.MessType = common.ReturnResMesType
//对resultMessage进行序列化
res_ByteSli, err := json.Marshal(resultMessage)
if err != nil {
fmt.Println("json.Marshal(resultMessage) err:", err)
return
}
//发送总消息(发送后,客户端那边还需要反序列化,客户端收到消息1,表明用户存在,收到消息0,表面用户不存在)
//因为使用分层模式(mvc),先创建一个Transfer实例,然后发送结果消息
tf := common.NewTransfer(p.Conn)
err = tf.WritePKG(res_ByteSli)
if err != nil {
fmt.Println("服务端 common.WritePKG(conn, res_ByteSli) err:", err)
return
}
if returnResMes.Code == 1 { //如果状态码被赋值1,说明用户存在,则可以进行一些逻辑操作
fmt.Printf("%v 连接到服务器\n", tf.Conn.RemoteAddr())
ReceiveMsg(tf.Conn)
}
}