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

      

  • 相关阅读:
    springboot系列九,springboot整合邮件服务、整合定时任务调度
    springboot系列八、springboot整合kafka
    springboot系列六、springboot配置错误页面及全局异常
    springboot系列五、springboot常用注解使用说明
    springboot系列四、配置模板引擎、配置热部署
    springboot系列三、springboot 单元测试、配置访问路径、多个配置文件和多环境配置,项目打包发布
    springboot系列二、springboot项目搭建
    springboot系列一、springboot产生背景及介绍
    kafka系列十、kafka常用管理命令
    Jmeter4.X
  • 原文地址:https://www.cnblogs.com/zh718594493/p/14221897.html
Copyright © 2020-2023  润新知