代码结构分析
2.目录结构
unitls/unitls.go代码
package unitls import ( "encoding/binary" "encoding/json" "fmt" "net" "common" ) type Transfer struct { Conn net.Conn buf [8096]byte } //读取包 func (this *Transfer ) ReadPkg() ( mes common.Message ,err error){ fmt.Println("读取客户端发送的连接"); _,err =this.Conn.Read(this.buf[:4]); if err !=nil { fmt.Println("conn.read is error"); return; } pkgLen:=binary.BigEndian.Uint32(this.buf[:4]);//根据读取buf[:4]里面转换为unit32类型 n,err:=this.Conn.Read(this.buf[:pkgLen]);//通过pkgLen读取多少个字节 if n != int(pkgLen) || err !=nil { return; } err = json.Unmarshal(this.buf[:pkgLen],&mes); if err != nil { fmt.Println("json.Unmarshal is error"); return; } return; } //写入包 func(this *Transfer )WritePkg(data []byte) (err error){ pkgLen := uint32(len(data));//数据包长度一个大包裹 binary.BigEndian.PutUint32(this.buf[:4],pkgLen);//将长度转化为字节序列 n,err:=this.Conn.Write(this.buf[:4]);//因为conn在写入的时候需要字节切片 & 网络传输中字节切片传输 if err != nil || n != 4 { fmt.Println("send len is error"); } //发送内容 n,err=this.Conn.Write(data); if n != int(pkgLen) || err != nil { fmt.Println("conn wrire is error"); return; } return; }
server/process/userProcess.go代码
package process import ( Common "common" "encoding/json" "fmt" "net" "unitls" ) type UserProcess struct { Conn net.Conn } //处理登录 func (this *UserProcess ) ServerProcessLogin( msg *Common.Message) (err error){ var Loginmes Common.LoginMes; err=json.Unmarshal([]byte(msg.Data),&Loginmes);//参数必须是字节切片后面必须是指针这个位置大坑 if err != nil { fmt.Println("json.Unmarshal is eroor"); return; } //声明返回的结构体 & 组装结构体 var resmsg Common.Message;//总结构体 resmsg.Type = Common.LoginResType; var loginresmsg Common.LoginResMes;//声明返回结构体类型 userId:=Loginmes.UserId; userName:=Loginmes.UserName; if userId == 100 && userName == "123456" { loginresmsg.Code=200; loginresmsg.Error="用户登录"; }else{ loginresmsg.Code=500; loginresmsg.Error="登录失败"; } //组装结构体 data,err:=json.Marshal(loginresmsg);//返回一个字节切片 if err != nil { fmt.Println("loginresmsg is error"); return; } resmsg.Data = string(data); data,err = json.Marshal(resmsg); if err != nil { fmt.Println("resmsg is error"); return; } tf:=unitls.Transfer{ Conn: this.Conn, } tf.WritePkg(data); return; }
server/main/processor.go代码
package main import ( Common "common" "fmt" "io" "net" "unitls" "redis/server/process" ) type Processor struct { Conn net.Conn } //根据客户端发送的消息类型进行处理 func (this *Processor ) serverProcessMes(msg *Common.Message) (err error){ switch msg.Type { case Common.LoginMesType: //创建一个用户实例 up:= &process.UserProcess{ Conn:this.Conn, } up.ServerProcessLogin(msg); case Common.LoginResType: default: fmt.Println("消息类型不对,无法处理"); return ; } return; } func (this * Processor ) process() (errs error){ for { tf:= unitls.Transfer{ Conn:this.Conn, } mes,err:=tf.ReadPkg(); if err != nil { if err == io.EOF { fmt.Println("客户端退出,服务器也退出"); return; }else{ fmt.Println("read pkg is error"); return; } } fmt.Println(mes); err=this.serverProcessMes(&mes);//发送请求处理 if err != nil { return; } } defer this.Conn.Close(); return ; }
server/main/main.go代码
package main import ( "fmt" "net" ) func startProcess(conn net.Conn){ processer:=&Processor{ Conn : conn, } err:=processer.process(); if err != nil { fmt.Println("start is error"); } } func main(){ fmt.Println("服务器在8889端口监听...."); listen,err:= net.Listen("tcp","0.0.0.0:8889"); defer listen.Close(); if err !=nil { fmt.Printf("net.Listen is error"); return; } for { fmt.Println("等待客户端的连接"); conn,err := listen.Accept(); if err != nil { fmt.Println("listen accept is err"); return; } go startProcess(conn); } }
client/main.go代码
package main import "fmt" var userId int; var userPwd string; func main(){ var key int; var loop=true; for loop { fmt.Println("----------------------欢迎多人聊天系统----------------------"); fmt.Println(" 1:登录聊天室"); fmt.Println(" 2:注册用户"); fmt.Println(" 3:退出系统"); fmt.Println(" 请选择(1-3):"); fmt.Scanf("%d ",&key); switch key { case 1: fmt.Println("登录聊天系统页面"); loop=false; case 2: fmt.Println("注册用户页面"); loop=false; case 3: fmt.Println("退出系统"); loop=false; default: fmt.Println("你的输入有误,请重新输入"); } } if key == 1 { fmt.Println("请输入用户ID:"); fmt.Scanf("%d ",&userId); fmt.Println("请输入用户密码:"); fmt.Scanf("%s ",&userPwd); login(userId,userPwd); } }
client/login.go代码
package main import ( Common "common" "encoding/binary" "encoding/json" "fmt" "net" "unitls" ) func login(userId int,userPwd string) (err error) { fmt.Printf("登录学生ID为%v 密码为%v",userId,userPwd); //连接远程服务器 conn,err:=net.Dial("tcp","localhost:8889"); if err != nil { fmt.Println("net.Dial is error"); } defer conn.Close(); var msg Common.Message; //1.设置消息类型 msg.Type=Common.LoginMesType;//设置登录结构体类型 //2.创建消息结构体 var logMes Common.LoginMes; logMes.UserId=userId; logMes.UserName=userPwd; data,err:= json.Marshal(logMes);//将消息内容序列化但是data是切片 if err != nil { fmt.Println("json.Marshal is error"); return; } msg.Data=string(data); //3.将全部消息序列化 data,err = json.Marshal(msg);//这是切片 if err != nil { fmt.Println("json.Marshal is error"); return; } //讨论如何发送 pkgLen:= uint32(len(data));//uint32的数字 var bytes [4]byte; //为了兼容不同设备之间需要发送字节序列 binary.BigEndian.PutUint32(bytes[0:4],pkgLen); n,err:=conn.Write(bytes[0:4]); if n !=4 || err != nil { fmt.Println("conn.Write() is error"); return; } //发送消息本身 _,err=conn.Write(data); if err != nil { fmt.Println("conn.write(data) is fail"); return; } tf:=unitls.Transfer{ Conn:conn, } msg,err=tf.ReadPkg(); if err !=nil { fmt.Println("readpagek is error"); return; } var loginRestype Common.LoginResMes; json.Unmarshal([]byte(msg.Data),&loginRestype); if loginRestype.Code == 200 { fmt.Println("登录成功"); }else{ fmt.Println("login is fail"); } return; }