zoukankan      html  css  js  c++  java
  • go实现聊天系统(四)

    代码结构分析

     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;
    }
  • 相关阅读:
    Vue-cli3中导入Cesium并配置
    Intellij IDEA中安装插件的两种方式
    Docker01——Ubuntu上安装Docker
    Java反射02——动态代理
    Java反射01——基本概念
    Docker安全配置问题
    马踏棋盘里面的一些小问题
    马踏棋盘算法用Java语言实现
    Android 中AIDL的使用与理解
    数据库技术中的触发器(Trigger)——和ContentObserver功能类似
  • 原文地址:https://www.cnblogs.com/zh718594493/p/14224052.html
Copyright © 2011-2022 走看看