go實現聊天系統(三)
阿新 • • 發佈:2021-01-02
配置檔案【通訊協議】
package main import ( Common "common" "encoding/json" "fmt" "io" "net" ) //處理登入 func serverProcessLogin(conn net.Conn, 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; } //下面傳送 Common.WritePkg(conn,data); return; } //根據客戶端傳送的訊息型別進行處理 func serverProcessMes(conn net.Conn,msg *Common.Message) (err error){ switch msg.Type { case Common.LoginMesType: serverProcessLogin(conn,msg); case Common.LoginResType: default: fmt.Println("訊息型別不對,無法處理"); return ; } return; } func process(conn net.Conn){ for { mes,err:= Common.ReadPkg(conn); if err != nil { if err == io.EOF { fmt.Println("客戶端退出,伺服器也退出"); return; }else{ fmt.Println("read pkg is error"); return; } } fmt.Println(mes); err=serverProcessMes(conn,&mes);//傳送請求處理 if err != nil { return; } } defer conn.Close(); } 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 process(conn); } }
2.客戶端
package main import "fmt" var userId int; var userPwd string; func main(){ var key int; var loop=true; for loop { 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("登入聊天系統頁面"); 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\n",&userId); fmt.Println("請輸入使用者密碼:"); fmt.Scanf("%s\n",&userPwd); login(userId,userPwd); } }
package main import ( Common "common" "encoding/binary" "encoding/json" "fmt" "net" ) 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; } msg,err=Common.ReadPkg(conn); 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; }
3.服務端
package main import ( Common "common" "encoding/json" "fmt" "io" "net" ) //處理登入 func serverProcessLogin(conn net.Conn, 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; } //下面傳送 Common.WritePkg(conn,data); return; } //根據客戶端傳送的訊息型別進行處理 func serverProcessMes(conn net.Conn,msg *Common.Message) (err error){ switch msg.Type { case Common.LoginMesType: serverProcessLogin(conn,msg); case Common.LoginResType: default: fmt.Println("訊息型別不對,無法處理"); return ; } return; } func process(conn net.Conn){ for { mes,err:= Common.ReadPkg(conn); if err != nil { if err == io.EOF { fmt.Println("客戶端退出,伺服器也退出"); return; }else{ fmt.Println("read pkg is error"); return; } } fmt.Println(mes); err=serverProcessMes(conn,&mes);//傳送請求處理 if err != nil { return; } } defer conn.Close(); } 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 process(conn); } }