go实现聊天系统(三)

配置文件【通讯协议】

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("			 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);
	}
}

 

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);
	}
}