client/login.go
package main
import (
"encoding/binary"
"encoding/json"
"fmt"
"net"
"testgo/chatrroom/common/message"
)
func login(userId int, userPwd string) (err error) {
//开始定协议
//fmt.Println("userId = %d,userPwd = %d", userId, userPwd)
//return nil
//1.连接服务器
conn, err := net.Dial("tcp", "localhost:8889")
if err != nil {
fmt.Println("net.Dial err", err)
return
}
//延时关闭
defer conn.Close()
//2.准备通过coon发送消息给服务
var mes message.Message
mes.Type = message.LoginMesType
//创建一个LoginMes结构体
var loginMes message.LoginMes
loginMes.UserId = userId
loginMes.UserPwd = userPwd
//4.将loginMes序列化
data, err := json.Marshal(loginMes)
if err != nil {
fmt.Println("json.Marshal err", err)
return
}
//5.把data给mes.Data字段
mes.Data = string(data)
//6.将mes序列化
data, err = json.Marshal(mes)
if err != nil {
fmt.Println("json.Marshal err", err)
return
}
//7. data就是我们要发送的东西
//7.1 先把data长度发送给服务器
//先获取data的长度,转化byte切片
var pkgLen uint32
pkgLen = uint32(len(data))
var buf [4]byte
binary.BigEndian.PutUint32(buf[0:4], pkgLen)
//发送长度
n, err := conn.Write(buf[:4])
if n != 4 || err != nil {
fmt.Println("coon.Write", err)
return
}
//fmt.Println("客户端,发送消息的长度成功 内容=%s", len(data), string(data))
//发送信息本身
_, err = conn.Write(data)
if err != nil {
fmt.Println("coon.Write(data)", err)
return
}
//time.Sleep(2 * time.Second)
//fmt.Println("休眠了2...")
//还需要处理服务端
mes, err = readPkg(conn)
//将mes的data部分反序列化成 LoginResMes
if err != nil {
fmt.Println("readPkg(conn) err=", err)
return
}
//将mes的data部分反序列化成LoginresMes
var loginResMes message.LoginResMes
err = json.Unmarshal([]byte(mes.Data), &loginResMes)
if loginResMes.Code == 200 {
fmt.Println("登录成功")
} else if loginResMes.Code == 500 {
fmt.Println(loginResMes.Error)
}
return
}
client/main.go
package main
import (
"fmt"
"os"
)
//定义两个变量 用户id 用户密码
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("退出系统")
os.Exit(0)
default:
fmt.Println("输入有误,请重试")
}
}
//根据用户的输入,显示新的提示信息
if key == 1 {
//用户要登录
fmt.Println("请输入用户id")
fmt.Scanln(&userId)
fmt.Println("请输入用户密码")
fmt.Scanln(&userPwd)
//先把登录的函数,写到另一个文件
login(userId, userPwd)
//if err != nil {
// fmt.Println("登录失败")
//} else {
// fmt.Println("登录成功")
//}
} else if key == 2 {
fmt.Println("进行用户注册")
}
}
cilent/utils.go
package main
import (
"encoding/binary"
"encoding/json"
"fmt"
"net"
"testgo/chatrroom/common/message"
)
func readPkg(conn net.Conn) (mes message.Message, err error) {
buf := make([]byte, 8096)
fmt.Println("读取客户端发送信息...")
//在conn没有被关闭的情况下,才会阻塞
_, err = conn.Read(buf[:4])
if err != nil {
// err = errors.New("read pkg header error")
return
}
//fmt.Println("读到的buf=", buf[:4])
var pkgLen uint32
pkgLen = binary.BigEndian.Uint32(buf[0:4])
//根据pkgLen读取消息内容
n, err := conn.Read(buf[:pkgLen])
if n != int(pkgLen) || err != nil {
//err = errors.New(" conn.Read error")
return
}
// 把pkgLen 反序列化 ->message.Message
err = json.Unmarshal(buf[:pkgLen], &mes)
if err != nil {
fmt.Println("json.Unmarshal err=", err)
return
}
return
}
func writePkg(conn net.Conn, data []byte) (err error) {
//先发送一个长度给对方
var pkgLen uint32
pkgLen = uint32(len(data))
var buf [4]byte
binary.BigEndian.PutUint32(buf[0:4], pkgLen)
//发送长度
n, err := conn.Write(buf[:4])
if n != 4 || err != nil {
fmt.Println("conn.Write err=", err)
return
}
//序列化
n, err = conn.Write(data)
if n != int(pkgLen) || err != nil {
fmt.Println("conn.Write(bytes) fail", err)
return
}
//发送消息本身
err = writePkg(conn, data)
return err
}
common/message/message.go
package message
const (
LoginMesType = "LoginMes"
LoginResMesType = "LoginResMes"
RegisterMesType = "RegisterMes"
)
type Message struct {
Type string `json:"type"` //消息类型
Data string `json:"data"` //消息的类型
}
// LoginMes 定义两个消息
type LoginMes struct {
UserId int `json:"userId"` //用户id
UserPwd string `json:"userPwd"` //用户密码
UserName string `json:"userName"` //用户名
}
type LoginResMes struct {
Code int `json:"code"` //状态码
Error string `json:"error"` //返回错误信息
}
type RegisterMes struct {
//...
}
server/main.go
package main
import (
"encoding/binary"
"encoding/json"
"fmt"
"io"
"net"
"testgo/chatrroom/common/message"
)
func readPkg(conn net.Conn) (mes message.Message, err error) {
buf := make([]byte, 8096)
fmt.Println("读取客户端发送信息...")
//在conn没有被关闭的情况下,才会阻塞
_, err = conn.Read(buf[:4])
if err != nil {
// err = errors.New("read pkg header error")
return
}
//fmt.Println("读到的buf=", buf[:4])
var pkgLen uint32
pkgLen = binary.BigEndian.Uint32(buf[0:4])
//根据pkgLen读取消息内容
n, err := conn.Read(buf[:pkgLen])
if n != int(pkgLen) || err != nil {
//err = errors.New(" conn.Read error")
return
}
// 把pkgLen 反序列化 ->message.Message
err = json.Unmarshal(buf[:pkgLen], &mes)
if err != nil {
fmt.Println("json.Unmarshal err=", err)
return
}
return
}
func writePkg(conn net.Conn, data []byte) (err error) {
//先发送一个长度给对方
var pkgLen uint32
pkgLen = uint32(len(data))
var buf [4]byte
binary.BigEndian.PutUint32(buf[0:4], pkgLen)
//发送长度
n, err := conn.Write(buf[:4])
if n != 4 || err != nil {
fmt.Println("conn.Write err=", err)
return
}
//发送data本身
n, err = conn.Write(data)
if n != int(pkgLen) || err != nil {
fmt.Println("conn.Write(bytes) fail", err)
return
}
return
}
//编写一个serverProcessLogin函数 处理登录请求
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 fail err=", err)
return
}
//声明一个resMes
var resMes message.Message
resMes.Type = message.LoginResMesType
//声明 LoginResMes
var loginResMes message.LoginResMes
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 err=", err)
return
}
//4.将data赋值给resMes
resMes.Data = string(data)
//5.对resMes序列化
data, err = json.Marshal(resMes)
if err != nil {
fmt.Println("json.marshal err=", err)
return
}
//3.发送data
err = writePkg(conn, data)
return err
}
//编写一个serverProcessMes函数
//根据客户端发送信息种类不同,决定调用那个函数处理
func serverProcessMes(conn net.Conn, mes *message.Message) (err error) {
switch mes.Type {
case message.LoginMesType:
//处理登录
err = serverProcessLogin(conn, mes)
case message.RegisterMesType:
//处理注册
default:
fmt.Println("消息类型不存在,无法处理")
}
return
}
func process(conn net.Conn) {
//读取客户端发送的信息
defer conn.Close()
//循环读取
for {
//读取数据包,直接封装成一个函数readPKG(),返回,Message,err
mes, err := readPkg(conn)
if err != nil {
if err == io.EOF {
fmt.Println("客户端退出,服务端也退出")
return
} else {
fmt.Println("readPkg(conn) err=", err)
return
}
}
//fmt.Println("message=", mes)
err = serverProcessMes(conn, &mes)
if err != nil {
return
}
}
}
func main() {
//提示信息
fmt.Println("服务器在8889监听")
listen, err := net.Listen("tcp", "0.0.0.0:8889")
defer listen.Close()
if err != nil {
fmt.Println("net.Listen err=", err)
return
}
//监听成功,等待额客户端连接服务器
for {
fmt.Println("等待客户端连接...")
conn, err := listen.Accept()
if err != nil {
fmt.Println("listen err=", err)
}
//一旦连接成功,则启动一个协程和客户端保持通讯..
go process(conn)
}
}